diff --git a/framework/res/xml/config.xml b/framework/res/xml/config.xml
index 935eda4f..6eea8d46 100644
--- a/framework/res/xml/config.xml
+++ b/framework/res/xml/config.xml
@@ -40,64 +40,9 @@
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/framework/src/org/apache/cordova/AccelListener.java b/framework/src/org/apache/cordova/AccelListener.java
deleted file mode 100755
index 934a8a8d..00000000
--- a/framework/src/org/apache/cordova/AccelListener.java
+++ /dev/null
@@ -1,285 +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 org.apache.cordova;
-
-import java.util.List;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-
-import android.os.Handler;
-import android.os.Looper;
-
-/**
- * This class listens to the accelerometer sensor and stores the latest
- * acceleration values x,y,z.
- */
-public class AccelListener extends CordovaPlugin 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;
-
- private float x,y,z; // most recent acceleration values
- private long timestamp; // time of most recent value
- private int status; // status of listener
- private int accuracy = SensorManager.SENSOR_STATUS_UNRELIABLE;
-
- private SensorManager sensorManager; // Sensor manager
- private Sensor mSensor; // Acceleration sensor returned by sensor manager
-
- private CallbackContext callbackContext; // Keeps track of the JS callback context.
-
- /**
- * 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 cordova The context of the main Activity.
- * @param webView The associated CordovaWebView.
- */
- @Override
- public void initialize(CordovaInterface cordova, CordovaWebView webView) {
- super.initialize(cordova, webView);
- this.sensorManager = (SensorManager) cordova.getActivity().getSystemService(Context.SENSOR_SERVICE);
- }
-
- /**
- * Executes the request.
- *
- * @param action The action to execute.
- * @param args The exec() arguments.
- * @param callbackId The callback id used when calling back into JavaScript.
- * @return Whether the action was valid.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
- if (action.equals("start")) {
- this.callbackContext = callbackContext;
- if (this.status != AccelListener.RUNNING) {
- // If not running, then this is an async call, so don't worry about waiting
- // We drop the callback onto our stack, call start, and let start and the sensor callback fire off the callback down the road
- this.start();
- }
- }
- else if (action.equals("stop")) {
- if (this.status == AccelListener.RUNNING) {
- this.stop();
- }
- } else {
- // Unsupported action
- return false;
- }
-
- PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT, "");
- result.setKeepCallback(true);
- callbackContext.sendPluginResult(result);
- return true;
- }
-
- /**
- * 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
- */
- private int start() {
- // If already starting or running, then just return
- if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
- return this.status;
- }
-
- this.setStatus(AccelListener.STARTING);
-
- // Get accelerometer from sensor manager
- List 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_UI);
- this.setStatus(AccelListener.STARTING);
- } else {
- this.setStatus(AccelListener.ERROR_FAILED_TO_START);
- this.fail(AccelListener.ERROR_FAILED_TO_START, "No sensors found to register accelerometer listening to.");
- return this.status;
- }
-
- // Set a timeout callback on the main thread.
- Handler handler = new Handler(Looper.getMainLooper());
- handler.postDelayed(new Runnable() {
- public void run() {
- AccelListener.this.timeout();
- }
- }, 2000);
-
- return this.status;
- }
-
- /**
- * Stop listening to acceleration sensor.
- */
- private void stop() {
- if (this.status != AccelListener.STOPPED) {
- this.sensorManager.unregisterListener(this);
- }
- this.setStatus(AccelListener.STOPPED);
- this.accuracy = SensorManager.SENSOR_STATUS_UNRELIABLE;
- }
-
- /**
- * Returns an error if the sensor hasn't started.
- *
- * Called two seconds after starting the listener.
- */
- private void timeout() {
- if (this.status == AccelListener.STARTING) {
- this.setStatus(AccelListener.ERROR_FAILED_TO_START);
- this.fail(AccelListener.ERROR_FAILED_TO_START, "Accelerometer could not be started.");
- }
- }
-
- /**
- * Called when the accuracy of the sensor has changed.
- *
- * @param sensor
- * @param accuracy
- */
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- // Only look at accelerometer events
- if (sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
- return;
- }
-
- // If not running, then just return
- if (this.status == AccelListener.STOPPED) {
- return;
- }
- this.accuracy = 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;
- }
- this.setStatus(AccelListener.RUNNING);
-
- if (this.accuracy >= SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM) {
-
- // 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.win();
- }
- }
-
- /**
- * Called when the view navigates.
- */
- @Override
- public void onReset() {
- if (this.status == AccelListener.RUNNING) {
- this.stop();
- }
- }
-
- // Sends an error back to JS
- private void fail(int code, String message) {
- // Error object
- JSONObject errorObj = new JSONObject();
- try {
- errorObj.put("code", code);
- errorObj.put("message", message);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- PluginResult err = new PluginResult(PluginResult.Status.ERROR, errorObj);
- err.setKeepCallback(true);
- callbackContext.sendPluginResult(err);
- }
-
- private void win() {
- // Success return object
- PluginResult result = new PluginResult(PluginResult.Status.OK, this.getAccelerationJSON());
- result.setKeepCallback(true);
- callbackContext.sendPluginResult(result);
- }
-
- private void setStatus(int status) {
- this.status = status;
- }
- private JSONObject getAccelerationJSON() {
- JSONObject r = new JSONObject();
- try {
- r.put("x", this.x);
- r.put("y", this.y);
- r.put("z", this.z);
- r.put("timestamp", this.timestamp);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- return r;
- }
-}
diff --git a/framework/src/org/apache/cordova/App.java b/framework/src/org/apache/cordova/App.java
deleted file mode 100755
index afdbf3f2..00000000
--- a/framework/src/org/apache/cordova/App.java
+++ /dev/null
@@ -1,221 +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 org.apache.cordova;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.LOG;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-
-/**
- * This class exposes methods in DroidGap that can be called from JavaScript.
- */
-public class App extends CordovaPlugin {
-
- /**
- * Executes the request and returns PluginResult.
- *
- * @param action The action to execute.
- * @param args JSONArry of arguments for the plugin.
- * @param callbackContext The callback context from which we were invoked.
- * @return A PluginResult object with a status and message.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- PluginResult.Status status = PluginResult.Status.OK;
- String result = "";
-
- try {
- if (action.equals("clearCache")) {
- this.clearCache();
- }
- else if (action.equals("show")) {
- // This gets called from JavaScript onCordovaReady to show the webview.
- // I recommend we change the name of the Message as spinner/stop is not
- // indicative of what this actually does (shows the webview).
- cordova.getActivity().runOnUiThread(new Runnable() {
- public void run() {
- webView.postMessage("spinner", "stop");
- }
- });
- }
- 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("overrideButton")) {
- this.overrideButton(args.getString(0), args.getBoolean(1));
- }
- else if (action.equals("overrideBackbutton")) {
- this.overrideBackbutton(args.getBoolean(0));
- }
- else if (action.equals("exitApp")) {
- this.exitApp();
- }
- callbackContext.sendPluginResult(new PluginResult(status, result));
- return true;
- } catch (JSONException e) {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
- return false;
- }
- }
-
- //--------------------------------------------------------------------------
- // LOCAL METHODS
- //--------------------------------------------------------------------------
-
- /**
- * Clear the resource cache.
- */
- public void clearCache() {
- this.webView.clearCache(true);
- }
-
- /**
- * 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 params = new HashMap();
- 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();
- }
- }
- this.webView.showWebPage(url, openExternal, clearHistory, params);
- }
-
- /**
- * Clear page history for the app.
- */
- public void clearHistory() {
- this.webView.clearHistory();
- }
-
- /**
- * Go to previous page displayed.
- * This is the same as pressing the backbutton on Android device.
- */
- public void backHistory() {
- cordova.getActivity().runOnUiThread(new Runnable() {
- public void run() {
- webView.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("App", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
- webView.bindButton(override);
- }
-
- /**
- * Override the default behavior of the Android volume buttons.
- * If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired.
- *
- * @param button volumeup, volumedown
- * @param override T=override, F=cancel override
- */
- public void overrideButton(String button, boolean override) {
- LOG.i("DroidGap", "WARNING: Volume Button Default Behaviour will be overridden. The volume event will be fired!");
- webView.bindButton(button, override);
- }
-
- /**
- * Return whether the Android back button is overridden by the user.
- *
- * @return boolean
- */
- public boolean isBackbuttonOverridden() {
- return webView.isBackButtonBound();
- }
-
- /**
- * Exit the Android application.
- */
- public void exitApp() {
- this.webView.postMessage("exit", null);
- }
-
-}
diff --git a/framework/src/org/apache/cordova/AudioHandler.java b/framework/src/org/apache/cordova/AudioHandler.java
deleted file mode 100644
index 20c3c4ef..00000000
--- a/framework/src/org/apache/cordova/AudioHandler.java
+++ /dev/null
@@ -1,362 +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 org.apache.cordova;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.DataResource;
-import android.content.Context;
-import android.media.AudioManager;
-
-import java.util.ArrayList;
-
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import java.util.HashMap;
-
-/**
- * This class called by CordovaActivity 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 CordovaPlugin {
-
- public static String TAG = "AudioHandler";
- HashMap players; // Audio player object
- ArrayList pausedForPhone; // Audio players that were paused when phone call came in
-
- /**
- * Constructor.
- */
- public AudioHandler() {
- this.players = new HashMap();
- this.pausedForPhone = new ArrayList();
- }
-
- public String getFilePath(String url, String source){
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(url, this.webView.pluginManager, cordova, source);
- return dataResource.getRealFile().getPath();
- }
-
- /**
- * Executes the request and returns PluginResult.
- * @param action The action to execute.
- * @param args JSONArry of arguments for the plugin.
- * @param callbackContext The callback context used when calling back into JavaScript.
- * @return A PluginResult object with a status and message.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- PluginResult.Status status = PluginResult.Status.OK;
- String result = "";
-
- if (action.equals("startRecordingAudio")) {
- this.startRecordingAudio(args.getString(0), getFilePath(args.getString(1), "AudioHandler.startRecordingAudio"));
- }
- else if (action.equals("stopRecordingAudio")) {
- this.stopRecordingAudio(args.getString(0));
- }
- else if (action.equals("startPlayingAudio")) {
- this.startPlayingAudio(args.getString(0), getFilePath(args.getString(1), "AudioHandler.startPlayingAudio"));
- }
- 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));
- callbackContext.sendPluginResult(new PluginResult(status, f));
- return true;
- }
- else if (action.equals("getDurationAudio")) {
- float f = this.getDurationAudio(args.getString(0), args.getString(1));
- callbackContext.sendPluginResult(new PluginResult(status, f));
- return true;
- }
- else if (action.equals("create")) {
- String id = args.getString(0);
- String src = getFilePath(args.getString(1), "AudioHandler.create");
- AudioPlayer audio = new AudioPlayer(this, id, src);
- this.players.put(id, audio);
- }
- else if (action.equals("release")) {
- boolean b = this.release(args.getString(0));
- callbackContext.sendPluginResult(new PluginResult(status, b));
- return true;
- }
- else { // Unrecognized action.
- return false;
- }
-
- callbackContext.sendPluginResult(new PluginResult(status, result));
-
- return true;
- }
-
- /**
- * Stop all audio players and recorders.
- */
- public void onDestroy() {
- for (AudioPlayer audio : this.players.values()) {
- audio.destroy();
- }
- this.players.clear();
- }
-
- /**
- * Stop all audio players and recorders on navigate.
- */
- @Override
- public void onReset() {
- onDestroy();
- }
-
- /**
- * Called when a message is sent to plugin.
- *
- * @param id The message id
- * @param data The message data
- * @return Object to stop propagation or null
- */
- public Object 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.STATE.MEDIA_RUNNING.ordinal()) {
- 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();
- }
- }
- return null;
- }
-
- //--------------------------------------------------------------------------
- // 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) {
- AudioPlayer audio = this.players.get(id);
- if ( audio == null) {
- audio = new AudioPlayer(this, id, file);
- 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();
- }
- }
-
- /**
- * 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, file);
- this.players.put(id, audio);
- }
- audio.startPlaying(file);
- }
-
- /**
- * Seek to a location.
- * @param id The id of the audio player
- * @param milliseconds 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, file);
- this.players.put(id, audio);
- return (audio.getDuration(file));
- }
- }
-
- /**
- * Set the audio device to be used for playback.
- *
- * @param output 1=earpiece, 2=speaker
- */
- @SuppressWarnings("deprecation")
- public void setAudioOutputDevice(int output) {
- AudioManager audiMgr = (AudioManager) this.cordova.getActivity().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
- */
- @SuppressWarnings("deprecation")
- public int getAudioOutputDevice() {
- AudioManager audiMgr = (AudioManager) this.cordova.getActivity().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);
- }
- }
-}
diff --git a/framework/src/org/apache/cordova/AudioPlayer.java b/framework/src/org/apache/cordova/AudioPlayer.java
deleted file mode 100644
index 01707280..00000000
--- a/framework/src/org/apache/cordova/AudioPlayer.java
+++ /dev/null
@@ -1,553 +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 org.apache.cordova;
-
-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.FileInputStream;
-import java.io.IOException;
-
-/**
- * This class implements the audio playback and recording capabilities used by Cordova.
- * It is called by the AudioHandler Cordova 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 {
-
- // AudioPlayer modes
- public enum MODE { NONE, PLAY, RECORD };
-
- // AudioPlayer states
- public enum STATE { MEDIA_NONE,
- MEDIA_STARTING,
- MEDIA_RUNNING,
- MEDIA_PAUSED,
- MEDIA_STOPPED,
- MEDIA_LOADING
- };
-
- private static final String LOG_TAG = "AudioPlayer";
-
- // 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 MODE mode = MODE.NONE; // Playback or Recording mode
- private STATE state = 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 player = null; // Audio player object
- private boolean prepareOnly = true; // playback after file prepare flag
- private int seekOnPrepared = 0; // seek to this location once media is prepared
-
- /**
- * Constructor.
- *
- * @param handler The audio handler object
- * @param id The id of this audio player
- */
- public AudioPlayer(AudioHandler handler, String id, String file) {
- this.handler = handler;
- this.id = id;
- this.audioFile = file;
- this.recorder = new MediaRecorder();
-
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.3gp";
- } else {
- this.tempFile = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/tmprecording.3gp";
- }
-
- }
-
- /**
- * Destroy player and stop audio playing or recording.
- */
- public void destroy() {
- // Stop any play or record
- if (this.player != null) {
- if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
- this.player.stop();
- this.setState(STATE.MEDIA_STOPPED);
- }
- this.player.release();
- this.player = 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) {
- switch (this.mode) {
- case PLAY:
- Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
- break;
- case NONE:
- this.audioFile = file;
- 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(STATE.MEDIA_RUNNING);
- return;
- } catch (IllegalStateException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
- break;
- case RECORD:
- Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+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);
-
- if (!file.startsWith("/")) {
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- file = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + file;
- } else {
- file = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/" + file;
- }
- }
-
- String logMsg = "renaming " + this.tempFile + " to " + file;
- Log.d(LOG_TAG, logMsg);
- if (!f.renameTo(new File(file))) Log.e(LOG_TAG, "FAILED " + logMsg);
- }
-
- /**
- * Stop recording and save to the file specified when recording started.
- */
- public void stopRecording() {
- if (this.recorder != null) {
- try{
- if (this.state == STATE.MEDIA_RUNNING) {
- this.recorder.stop();
- this.setState(STATE.MEDIA_STOPPED);
- }
- this.recorder.reset();
- this.moveFile(this.audioFile);
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- //==========================================================================
- // Playback
- //==========================================================================
-
- /**
- * Start or resume playing audio file.
- *
- * @param file The name of the audio file.
- */
- public void startPlaying(String file) {
- if (this.readyPlayer(file) && this.player != null) {
- this.player.start();
- this.setState(STATE.MEDIA_RUNNING);
- this.seekOnPrepared = 0; //insures this is always reset
- } else {
- this.prepareOnly = false;
- }
- }
-
- /**
- * Seek or jump to a new time in the track.
- */
- public void seekToPlaying(int milliseconds) {
- if (this.readyPlayer(this.audioFile)) {
- this.player.seekTo(milliseconds);
- Log.d(LOG_TAG, "Send a onStatus update for the new seek");
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + milliseconds / 1000.0f + ");");
- }
- else {
- this.seekOnPrepared = milliseconds;
- }
- }
-
- /**
- * Pause playing.
- */
- public void pausePlaying() {
-
- // If playing, then pause
- if (this.state == STATE.MEDIA_RUNNING && this.player != null) {
- this.player.pause();
- this.setState(STATE.MEDIA_PAUSED);
- }
- else {
- Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: " + this.state.ordinal());
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
- }
- }
-
- /**
- * Stop playing the audio file.
- */
- public void stopPlaying() {
- if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
- this.player.pause();
- this.player.seekTo(0);
- Log.d(LOG_TAG, "stopPlaying is calling stopped");
- this.setState(STATE.MEDIA_STOPPED);
- }
- else {
- Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: " + this.state.ordinal());
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
- }
- }
-
- /**
- * Callback to be invoked when playback of a media source has completed.
- *
- * @param player The MediaPlayer that reached the end of the file
- */
- public void onCompletion(MediaPlayer player) {
- Log.d(LOG_TAG, "on completion is calling stopped");
- this.setState(STATE.MEDIA_STOPPED);
- }
-
- /**
- * Get current position of playback.
- *
- * @return position in msec or -1 if not playing
- */
- public long getCurrentPosition() {
- if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
- int curPos = this.player.getCurrentPosition();
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/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.player != 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 player The MediaPlayer that is ready for playback
- */
- public void onPrepared(MediaPlayer player) {
- // Listen for playback completion
- this.player.setOnCompletionListener(this);
- // seek to any location received while not prepared
- this.seekToPlaying(this.seekOnPrepared);
- // If start playing after prepared
- if (!this.prepareOnly) {
- this.player.start();
- this.setState(STATE.MEDIA_RUNNING);
- this.seekOnPrepared = 0; //reset only when played
- } else {
- this.setState(STATE.MEDIA_STARTING);
- }
- // Save off duration
- this.duration = getDurationInSeconds();
- // reset prepare only flag
- this.prepareOnly = true;
-
- // Send status notification to JavaScript
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/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.player.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 player 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 player, int arg1, int arg2) {
- Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2 + ")");
-
- // TODO: Not sure if this needs to be sent?
- this.player.stop();
- this.player.release();
-
- // Send error notification to JavaScript
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":" + arg1 + "});");
- return false;
- }
-
- /**
- * Set the state and send it to JavaScript.
- *
- * @param state
- */
- private void setState(STATE state) {
- if (this.state != state) {
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + state.ordinal() + ");");
- }
- this.state = state;
- }
-
- /**
- * Set the mode and send it to JavaScript.
- *
- * @param state
- */
- private void setMode(MODE mode) {
- if (this.mode != mode) {
- //mode is not part of the expected behavior, so no notification
- //this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + mode + ");");
- }
- this.mode = mode;
- }
-
- /**
- * Get the audio state.
- *
- * @return int
- */
- public int getState() {
- return this.state.ordinal();
- }
-
- /**
- * Set the volume for audio player
- *
- * @param volume
- */
- public void setVolume(float volume) {
- this.player.setVolume(volume, volume);
- }
-
- /**
- * attempts to put the player in play mode
- * @return true if in playmode, false otherwise
- */
- private boolean playMode() {
- switch(this.mode) {
- case NONE:
- this.setMode(MODE.PLAY);
- break;
- case PLAY:
- break;
- case RECORD:
- Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
- return false; //player is not ready
- }
- return true;
- }
-
- /**
- * attempts to initialize the media player for playback
- * @param file the file to play
- * @return false if player not ready, reports if in wrong mode or state
- */
- private boolean readyPlayer(String file) {
- if (playMode()) {
- switch (this.state) {
- case MEDIA_NONE:
- if (this.player == null) {
- this.player = new MediaPlayer();
- }
- try {
- this.loadAudioFile(file);
- } catch (Exception e) {
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
- }
- return false;
- case MEDIA_LOADING:
- //cordova js is not aware of MEDIA_LOADING, so we send MEDIA_STARTING instead
- Log.d(LOG_TAG, "AudioPlayer Loading: startPlaying() called during media preparation: " + STATE.MEDIA_STARTING.ordinal());
- this.prepareOnly = false;
- return false;
- case MEDIA_STARTING:
- case MEDIA_RUNNING:
- case MEDIA_PAUSED:
- return true;
- case MEDIA_STOPPED:
- //if we are readying the same file
- if (this.audioFile.compareTo(file) == 0) {
- //reset the audio file
- player.seekTo(0);
- player.pause();
- return true;
- } else {
- //reset the player
- this.player.reset();
- try {
- this.loadAudioFile(file);
- } catch (Exception e) {
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
- }
- //if we had to prepare= the file, we won't be in the correct state for playback
- return false;
- }
- default:
- Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: " + this.state);
- this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
- }
- }
- return false;
- }
-
- /**
- * load audio file
- * @throws IOException
- * @throws IllegalStateException
- * @throws SecurityException
- * @throws IllegalArgumentException
- */
- private void loadAudioFile(String file) throws IllegalArgumentException, SecurityException, IllegalStateException, IOException {
- if (this.isStreaming(file)) {
- this.player.setDataSource(file);
- this.player.setAudioStreamType(AudioManager.STREAM_MUSIC);
- //if it's a streaming file, play mode is implied
- this.setMode(MODE.PLAY);
- this.setState(STATE.MEDIA_STARTING);
- this.player.setOnPreparedListener(this);
- this.player.prepareAsync();
- }
- else {
- if (file.startsWith("/android_asset/")) {
- String f = file.substring(15);
- android.content.res.AssetFileDescriptor fd = this.handler.cordova.getActivity().getAssets().openFd(f);
- this.player.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
- }
- else {
- File fp = new File(file);
- if (fp.exists()) {
- FileInputStream fileInputStream = new FileInputStream(file);
- this.player.setDataSource(fileInputStream.getFD());
- }
- else {
- this.player.setDataSource("/sdcard/" + file);
- }
- }
- this.setState(STATE.MEDIA_STARTING);
- this.player.setOnPreparedListener(this);
- this.player.prepare();
-
- // Get duration
- this.duration = getDurationInSeconds();
- }
- }
-}
diff --git a/framework/src/org/apache/cordova/BatteryListener.java b/framework/src/org/apache/cordova/BatteryListener.java
deleted file mode 100755
index 85558c2a..00000000
--- a/framework/src/org/apache/cordova/BatteryListener.java
+++ /dev/null
@@ -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 org.apache.cordova;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.Log;
-
-public class BatteryListener extends CordovaPlugin {
-
- private static final String LOG_TAG = "BatteryManager";
-
- BroadcastReceiver receiver;
-
- private CallbackContext batteryCallbackContext = null;
-
- /**
- * Constructor.
- */
- public BatteryListener() {
- this.receiver = null;
- }
-
- /**
- * Executes the request.
- *
- * @param action The action to execute.
- * @param args JSONArry of arguments for the plugin.
- * @param callbackContext The callback context used when calling back into JavaScript.
- * @return True if the action was valid, false if not.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
- if (action.equals("start")) {
- if (this.batteryCallbackContext != null) {
- callbackContext.error( "Battery listener already running.");
- return true;
- }
- this.batteryCallbackContext = callbackContext;
-
- // 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);
- }
- };
- cordova.getActivity().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);
- callbackContext.sendPluginResult(pluginResult);
- return true;
- }
-
- else if (action.equals("stop")) {
- removeBatteryListener();
- this.sendUpdate(new JSONObject(), false); // release status callback in JS side
- this.batteryCallbackContext = null;
- callbackContext.success();
- return true;
- }
-
- return false;
- }
-
- /**
- * Stop battery receiver.
- */
- public void onDestroy() {
- removeBatteryListener();
- }
-
- /**
- * Stop battery receiver.
- */
- public void onReset() {
- removeBatteryListener();
- }
-
- /**
- * Stop the battery receiver and set it to null.
- */
- private void removeBatteryListener() {
- if (this.receiver != null) {
- try {
- this.cordova.getActivity().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.batteryCallbackContext != null) {
- PluginResult result = new PluginResult(PluginResult.Status.OK, info);
- result.setKeepCallback(keepCallback);
- this.batteryCallbackContext.sendPluginResult(result);
- }
- }
-}
diff --git a/framework/src/org/apache/cordova/CameraLauncher.java b/framework/src/org/apache/cordova/CameraLauncher.java
deleted file mode 100755
index 1974dd71..00000000
--- a/framework/src/org/apache/cordova/CameraLauncher.java
+++ /dev/null
@@ -1,824 +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 org.apache.cordova;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.DataResource;
-import org.apache.cordova.api.LOG;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-
-import android.app.Activity;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Matrix;
-import android.graphics.Bitmap.CompressFormat;
-import android.media.MediaScannerConnection;
-import android.media.MediaScannerConnection.MediaScannerConnectionClient;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.util.Log;
-
-/**
- * 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 CordovaPlugin implements MediaScannerConnectionClient {
-
- 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 NATIVE_URI = 2; // On Android, this is the same as FILE_URI
-
- 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
- private boolean saveToPhotoAlbum; // Should the picture be saved to the device's photo album
- private boolean correctOrientation; // Should the pictures orientation be corrected
- //private boolean allowEdit; // Should we allow the user to crop the image. UNUSED.
-
- public CallbackContext callbackContext;
- private int numPics;
-
- private MediaScannerConnection conn; // Used to update gallery app with newly-written files
- private Uri scanMe; // Uri of image to be added to content store
-
- //This should never be null!
- //private CordovaInterface cordova;
-
- /**
- * Constructor.
- */
- public CameraLauncher() {
- }
-
-// public void setContext(CordovaInterface mCtx) {
-// super.setContext(mCtx);
-// if (CordovaInterface.class.isInstance(mCtx))
-// cordova = (CordovaInterface) mCtx;
-// else
-// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
-// }
-
- /**
- * Executes the request and returns PluginResult.
- *
- * @param action The action to execute.
- * @param args JSONArry of arguments for the plugin.
- * @param callbackContext The callback id used when calling back into JavaScript.
- * @return A PluginResult object with a status and message.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- this.callbackContext = callbackContext;
-
- if (action.equals("takePicture")) {
- int srcType = CAMERA;
- int destType = FILE_URI;
- this.saveToPhotoAlbum = false;
- this.targetHeight = 0;
- this.targetWidth = 0;
- this.encodingType = JPEG;
- this.mediaType = PICTURE;
- this.mQuality = 80;
-
- this.mQuality = args.getInt(0);
- destType = args.getInt(1);
- srcType = args.getInt(2);
- this.targetWidth = args.getInt(3);
- this.targetHeight = args.getInt(4);
- this.encodingType = args.getInt(5);
- this.mediaType = args.getInt(6);
- //this.allowEdit = args.getBoolean(7); // This field is unused.
- this.correctOrientation = args.getBoolean(8);
- this.saveToPhotoAlbum = args.getBoolean(9);
-
- // If the user specifies a 0 or smaller width/height
- // make it -1 so later comparisons succeed
- if (this.targetWidth < 1) {
- this.targetWidth = -1;
- }
- if (this.targetHeight < 1) {
- this.targetHeight = -1;
- }
-
- 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);
- callbackContext.sendPluginResult(r);
- return true;
- }
- return false;
- }
-
- //--------------------------------------------------------------------------
- // LOCAL METHODS
- //--------------------------------------------------------------------------
-
- /**
- * Take a picture with the camera.
- * When an image is captured or the camera view is cancelled, the result is returned
- * in CordovaActivity.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(whichContentStore()).getCount();
-
- // Display camera
- Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
-
- // Specify file so that large image is captured and returned
- File photo = createCaptureFile(encodingType);
- intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
- this.imageUri = Uri.fromFile(photo);
-
- if (this.cordova != null) {
- this.cordova.startActivityForResult((CordovaPlugin) this, intent, (CAMERA + 1) * 16 + returnType + 1);
- }
-// else
-// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
- }
-
- /**
- * 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(this.cordova.getActivity()), ".Pic.jpg");
- } else if (encodingType == PNG) {
- photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), ".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);
- if (this.cordova != null) {
- this.cordova.startActivityForResult((CordovaPlugin) this, Intent.createChooser(intent,
- new String(title)), (srcType + 1) * 16 + returnType + 1);
- }
- }
-
- /**
- * 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;
- int rotate = 0;
-
- // 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();
- try {
- if (this.encodingType == JPEG) {
- exif.createInFile(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/.Pic.jpg");
- exif.readExifData();
- rotate = exif.getOrientation();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- Bitmap bitmap = null;
- Uri uri = null;
-
- // If sending base64 image back
- if (destType == DATA_URL) {
- bitmap = getScaledBitmap(imageUri.toString());
- if (bitmap == null) {
- // Try to get the bitmap from intent.
- bitmap = (Bitmap)intent.getExtras().get("data");
- }
-
- // Double-check the bitmap.
- if (bitmap == null) {
- Log.d(LOG_TAG, "I either have a null image path or bitmap");
- this.failPicture("Unable to create bitmap!");
- return;
- }
-
- if (rotate != 0 && this.correctOrientation) {
- bitmap = getRotatedBitmap(rotate, bitmap, exif);
- }
-
- this.processPicture(bitmap);
- checkForDuplicateImage(DATA_URL);
- }
-
- // If sending filename back
- else if (destType == FILE_URI || destType == NATIVE_URI) {
- if (this.saveToPhotoAlbum) {
- Uri inputUri = getUriFromMediaStore();
- //Just because we have a media URI doesn't mean we have a real file, we need to make it
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(inputUri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
- File file = dataResource.getRealFile();
- uri = Uri.fromFile(file);
- } else {
- uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
- }
-
- if (uri == null) {
- this.failPicture("Error capturing image - no media storage found.");
- }
-
- // If all this is true we shouldn't compress the image.
- if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 &&
- !this.correctOrientation) {
- writeUncompressedImage(uri);
-
- this.callbackContext.success(uri.toString());
- } else {
- bitmap = getScaledBitmap(imageUri.toString());
-
- if (rotate != 0 && this.correctOrientation) {
- bitmap = getRotatedBitmap(rotate, bitmap, exif);
- }
-
- // Add compressed version of captured image to returned media store Uri
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
- OutputStream os = dataResource.getOutputStream();
- bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
- os.close();
-
- // Restore exif data to file
- if (this.encodingType == JPEG) {
- String exifPath;
- if (this.saveToPhotoAlbum) {
- exifPath = dataResource.getRealFile().getPath();
- } else {
- exifPath = uri.getPath();
- }
- exif.createOutFile(exifPath);
- exif.writeExifData();
- }
-
- }
- // Send Uri back to JavaScript for viewing image
- this.callbackContext.success(uri.toString());
- }
-
- this.cleanup(FILE_URI, this.imageUri, uri, bitmap);
- bitmap = null;
-
- } 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();
-
- // 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.callbackContext.success(uri.toString());
- }
- else {
- // This is a special case to just return the path as no scaling,
- // rotating, nor compressing needs to be done
- if (this.targetHeight == -1 && this.targetWidth == -1 &&
- (destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation) {
- this.callbackContext.success(uri.toString());
- } else {
- String uriString = uri.toString();
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
- // Get the path to the image. Makes loading so much easier.
- String mimeType = dataResource.getMimeType();
- // If we don't have a valid image so quit.
- if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) {
- Log.d(LOG_TAG, "I either have a null image path or bitmap");
- this.failPicture("Unable to retrieve path to picture!");
- return;
- }
- Bitmap bitmap = null;
- try {
- bitmap = getScaledBitmap(uriString);
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (bitmap == null) {
- Log.d(LOG_TAG, "I either have a null image path or bitmap");
- this.failPicture("Unable to create bitmap!");
- return;
- }
-
- if (this.correctOrientation) {
- rotate = getImageOrientation(uri);
- if (rotate != 0) {
- Matrix matrix = new Matrix();
- matrix.setRotate(rotate);
- bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
- }
- }
-
- // If sending base64 image back
- if (destType == DATA_URL) {
- this.processPicture(bitmap);
- }
-
- // If sending filename back
- else if (destType == FILE_URI || destType == NATIVE_URI) {
- // Do we need to scale the returned file
- if (this.targetHeight > 0 && this.targetWidth > 0) {
- try {
- // Create an ExifHelper to save the exif data that is lost during compression
- String resizePath = DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/resize.jpg";
- // Some content: URIs do not map to file paths (e.g. picasa).
- File realFile = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent").getRealFile();
- String realPath = realFile != null? realFile.getPath() : null;
- ExifHelper exif = new ExifHelper();
- if (realPath != null && this.encodingType == JPEG) {
- try {
- exif.createInFile(realPath);
- exif.readExifData();
- rotate = exif.getOrientation();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- OutputStream os = new FileOutputStream(resizePath);
- bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
- os.close();
-
- // Restore exif data to file
- if (realPath != null && this.encodingType == JPEG) {
- exif.createOutFile(resizePath);
- exif.writeExifData();
- }
-
- // 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.callbackContext.success("file://" + resizePath + "?" + System.currentTimeMillis());
- } catch (Exception e) {
- e.printStackTrace();
- this.failPicture("Error retrieving image.");
- }
- }
- else {
- this.callbackContext.success(uri.toString());
- }
- }
- if (bitmap != null) {
- bitmap.recycle();
- bitmap = null;
- }
- System.gc();
- }
- }
- }
- else if (resultCode == Activity.RESULT_CANCELED) {
- this.failPicture("Selection cancelled.");
- }
- else {
- this.failPicture("Selection did not complete!");
- }
- }
- }
-
- private int getImageOrientation(Uri uri) {
- String[] cols = { MediaStore.Images.Media.ORIENTATION };
- Cursor cursor = cordova.getActivity().getContentResolver().query(uri,
- cols, null, null, null);
- int rotate = 0;
- if (cursor != null) {
- cursor.moveToPosition(0);
- rotate = cursor.getInt(0);
- cursor.close();
- }
- return rotate;
- }
-
- /**
- * Figure out if the bitmap should be rotated. For instance if the picture was taken in
- * portrait mode
- *
- * @param rotate
- * @param bitmap
- * @return rotated bitmap
- */
- private Bitmap getRotatedBitmap(int rotate, Bitmap bitmap, ExifHelper exif) {
- Matrix matrix = new Matrix();
- if (rotate == 180) {
- matrix.setRotate(rotate);
- } else {
- matrix.setRotate(rotate, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2);
- }
- bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
- exif.resetOrientation();
- return bitmap;
- }
-
- /**
- * In the special case where the default width, height and quality are unchanged
- * we just write the file out to disk saving the expensive Bitmap.compress function.
- *
- * @param uri
- * @throws FileNotFoundException
- * @throws IOException
- */
- private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
- IOException {
- DataResource inputDataResource = DataResource.initiateNewDataRequestForUri(imageUri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage");
- InputStream fis = inputDataResource.getInputStream();
- DataResource outDataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage");
- OutputStream os = outDataResource.getOutputStream();
- if(fis == null) {
- throw new FileNotFoundException("Could not get the input file");
- } else if(os == null) {
- throw new FileNotFoundException("Could not get the output file");
- }
- byte[] buffer = new byte[4096];
- int len;
- while ((len = fis.read(buffer)) != -1) {
- os.write(buffer, 0, len);
- }
- os.flush();
- os.close();
- fis.close();
- }
-
- /**
- * Create entry in media store for image
- *
- * @return uri
- */
- private Uri getUriFromMediaStore() {
- ContentValues values = new ContentValues();
- values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
- Uri uri;
- try {
- uri = this.cordova.getActivity().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.cordova.getActivity().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.");
- return null;
- }
- }
- return uri;
- }
-
- /**
- * Return a scaled bitmap based on the target width and height
- *
- * @param imagePath
- * @return
- * @throws IOException
- */
- private Bitmap getScaledBitmap(String imageUrl) throws IOException {
- // If no new width or height were specified return the original bitmap
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(imageUrl, webView.pluginManager, cordova, "CameraLauncher.getScaledBitmap");
- if (this.targetWidth <= 0 && this.targetHeight <= 0) {
- return BitmapFactory.decodeStream(dataResource.getInputStream());
- }
-
- // figure out the original width and height of the image
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeStream(dataResource.getInputStream(), null, options);
-
- //CB-2292: WTF? Why is the width null?
- if(options.outWidth == 0 || options.outHeight == 0)
- {
- return null;
- }
-
- // determine the correct aspect ratio
- int[] widthHeight = calculateAspectRatio(options.outWidth, options.outHeight);
-
- // Load in the smallest bitmap possible that is closest to the size we want
- options.inJustDecodeBounds = false;
- options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
- Bitmap unscaledBitmap = BitmapFactory.decodeStream(dataResource.getInputStream(), null, options);
- if (unscaledBitmap == null) {
- return null;
- }
-
- return Bitmap.createScaledBitmap(unscaledBitmap, widthHeight[0], widthHeight[1], true);
- }
-
- /**
- * Maintain the aspect ratio so the resulting image does not look smooshed
- *
- * @param origWidth
- * @param origHeight
- * @return
- */
- public int[] calculateAspectRatio(int origWidth, int origHeight) {
- int newWidth = this.targetWidth;
- int newHeight = this.targetHeight;
-
- // If no new width or height were specified return the original bitmap
- if (newWidth <= 0 && newHeight <= 0) {
- newWidth = origWidth;
- newHeight = origHeight;
- }
- // 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;
- }
- }
-
- int[] retval = new int[2];
- retval[0] = newWidth;
- retval[1] = newHeight;
- return retval;
- }
-
- /**
- * Figure out what ratio we can load our image into memory at while still being bigger than
- * our desired width and height
- *
- * @param srcWidth
- * @param srcHeight
- * @param dstWidth
- * @param dstHeight
- * @return
- */
- public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight) {
- final float srcAspect = (float)srcWidth / (float)srcHeight;
- final float dstAspect = (float)dstWidth / (float)dstHeight;
-
- if (srcAspect > dstAspect) {
- return srcWidth / dstWidth;
- } else {
- return srcHeight / dstHeight;
- }
- }
-
- /**
- * Creates a cursor that can be used to determine how many images we have.
- *
- * @return a cursor
- */
- private Cursor queryImgDB(Uri contentStore) {
- return this.cordova.getActivity().getContentResolver().query(
- contentStore,
- new String[] { MediaStore.Images.Media._ID },
- null,
- null,
- null);
- }
-
- /**
- * Cleans up after picture taking. Checking for duplicates and that kind of stuff.
- * @param newImage
- */
- private void cleanup(int imageType, Uri oldImage, Uri newImage, Bitmap bitmap) {
- if (bitmap != null) {
- bitmap.recycle();
- }
-
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(oldImage, webView.pluginManager, cordova, "CameraLauncher.cleanup");
- File file = dataResource.getRealFile();
- if(file != null) {
- // Clean up initial camera-written image file.
- file.delete();
-
- checkForDuplicateImage(imageType);
- // Scan for the gallery to update pic refs in gallery
- if (this.saveToPhotoAlbum && newImage != null) {
- this.scanForGallery(newImage);
- }
-
- System.gc();
- }
- }
-
- /**
- * 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;
- Uri contentStore = whichContentStore();
- Cursor cursor = queryImgDB(contentStore);
- int currentNumOfImages = cursor.getCount();
-
- if (type == FILE_URI && this.saveToPhotoAlbum) {
- 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)));
- if (diff == 2) {
- id--;
- }
- Uri uri = Uri.parse(contentStore + "/" + id);
- this.cordova.getActivity().getContentResolver().delete(uri, null, null);
- }
- }
-
- /**
- * Determine if we are storing the images in internal or external storage
- * @return Uri
- */
- private Uri whichContentStore() {
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- return android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
- } else {
- return android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI;
- }
- }
-
- /**
- * 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.callbackContext.success(js_out);
- 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.callbackContext.error(err);
- }
-
- private void scanForGallery(Uri newImage) {
- this.scanMe = newImage;
- if(this.conn != null) {
- this.conn.disconnect();
- }
- this.conn = new MediaScannerConnection(this.cordova.getActivity().getApplicationContext(), this);
- conn.connect();
- }
-
- public void onMediaScannerConnected() {
- try{
- this.conn.scanFile(this.scanMe.toString(), "image/*");
- } catch (java.lang.IllegalStateException e){
- LOG.e(LOG_TAG, "Can't scan file in MediaScanner after taking picture");
- }
-
- }
-
- public void onScanCompleted(String path, Uri uri) {
- this.conn.disconnect();
- }
-}
diff --git a/framework/src/org/apache/cordova/Capture.java b/framework/src/org/apache/cordova/Capture.java
deleted file mode 100644
index d7ad419e..00000000
--- a/framework/src/org/apache/cordova/Capture.java
+++ /dev/null
@@ -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 org.apache.cordova;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import android.os.Build;
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.DataResource;
-import org.apache.cordova.api.LOG;
-import org.apache.cordova.api.PluginResult;
-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.database.Cursor;
-import android.graphics.BitmapFactory;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.util.Log;
-
-public class Capture extends CordovaPlugin {
-
- private static final String VIDEO_3GPP = "video/3gpp";
- private static final String VIDEO_MP4 = "video/mp4";
- 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 CallbackContext callbackContext; // The callback context from which we were invoked.
- 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 int numPics; // Number of pictures before capture activity
-
- //private CordovaInterface cordova;
-
-// public void setContext(Context mCtx)
-// {
-// if (CordovaInterface.class.isInstance(mCtx))
-// cordova = (CordovaInterface) mCtx;
-// else
-// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
-// }
-
- @Override
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- this.callbackContext = callbackContext;
- 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")) {
- JSONObject obj = getFormatData(args.getString(0), args.getString(1));
- callbackContext.success(obj);
- return true;
- }
- else if (action.equals("captureAudio")) {
- this.captureAudio();
- }
- else if (action.equals("captureImage")) {
- this.captureImage();
- }
- else if (action.equals("captureVideo")) {
- this.captureVideo(duration);
- }
- else {
- return false;
- }
-
- return true;
- }
-
- /**
- * 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) throws JSONException {
- JSONObject obj = new JSONObject();
- // 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("") || "null".equals(mimeType)) {
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "Capture.dataResource");
- mimeType = dataResource.getMimeType();
- }
- 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) || mimeType.equals(VIDEO_MP4)) {
- obj = getAudioVideoData(filePath, obj, true);
- }
- 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 {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "Capture.getImageData");
- BitmapFactory.decodeFile(dataResource.getRealFile().getPath(), options);
- obj.put("height", options.outHeight);
- obj.put("width", options.outWidth);
- 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() / 1000);
- 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.cordova.startActivityForResult((CordovaPlugin) this, intent, CAPTURE_AUDIO);
- }
-
- /**
- * Sets up an intent to capture images. Result handled by onActivityResult()
- */
- private void captureImage() {
- // Save the number of images currently on disk for later
- this.numPics = queryImgDB(whichContentStore()).getCount();
-
- 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(this.cordova.getActivity()), "Capture.jpg");
- intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
-
- this.cordova.startActivityForResult((CordovaPlugin) 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);
-
- if(Build.VERSION.SDK_INT > 8){
- intent.putExtra("android.intent.extra.durationLimit", duration);
- }
- this.cordova.startActivityForResult((CordovaPlugin) 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.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
- } 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 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.cordova.getActivity().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.cordova.getActivity().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;
- }
- }
- FileInputStream fis = new FileInputStream(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/Capture.jpg");
- OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
- byte[] buffer = new byte[4096];
- int len;
- while ((len = fis.read(buffer)) != -1) {
- os.write(buffer, 0, len);
- }
- os.flush();
- os.close();
- fis.close();
-
- // Add image to results
- results.put(createMediaFile(uri));
-
- checkForDuplicateImage();
-
- if (results.length() >= limit) {
- // Send Uri back to JavaScript for viewing image
- this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
- } 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.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
- } 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.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
- }
- // 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.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
- }
- // 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) {
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(data, webView.pluginManager, cordova, "Capture.createMediaFile");
- File fp = dataResource.getRealFile();
- JSONObject obj = new JSONObject();
-
- try {
- // File properties
- obj.put("name", fp.getName());
- obj.put("fullPath", "file://" + 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", dataResource.getMimeType());
- }
-
- 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.callbackContext.error(err);
- }
-
-
- /**
- * Creates a cursor that can be used to determine how many images we have.
- *
- * @return a cursor
- */
- private Cursor queryImgDB(Uri contentStore) {
- return this.cordova.getActivity().getContentResolver().query(
- contentStore,
- 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.
- */
- private void checkForDuplicateImage() {
- Uri contentStore = whichContentStore();
- Cursor cursor = queryImgDB(contentStore);
- int currentNumOfImages = cursor.getCount();
-
- // delete the duplicate file if the difference is 2
- if ((currentNumOfImages - numPics) == 2) {
- cursor.moveToLast();
- int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1;
- Uri uri = Uri.parse(contentStore + "/" + id);
- this.cordova.getActivity().getContentResolver().delete(uri, null, null);
- }
- }
-
- /**
- * Determine if we are storing the images in internal or external storage
- * @return Uri
- */
- private Uri whichContentStore() {
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- return android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
- } else {
- return android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI;
- }
- }
-}
diff --git a/framework/src/org/apache/cordova/CompassListener.java b/framework/src/org/apache/cordova/CompassListener.java
deleted file mode 100755
index 401e0536..00000000
--- a/framework/src/org/apache/cordova/CompassListener.java
+++ /dev/null
@@ -1,295 +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 org.apache.cordova;
-
-import java.util.List;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.content.Context;
-
-import android.os.Handler;
-import android.os.Looper;
-
-/**
- * This class listens to the compass sensor and stores the latest heading value.
- */
-public class CompassListener extends CordovaPlugin 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
-
- private CallbackContext callbackContext;
-
- /**
- * Constructor.
- */
- public CompassListener() {
- this.heading = 0;
- 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 cordova The context of the main Activity.
- * @param webView The CordovaWebView Cordova is running in.
- */
- public void initialize(CordovaInterface cordova, CordovaWebView webView) {
- super.initialize(cordova, webView);
- this.sensorManager = (SensorManager) cordova.getActivity().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 callbackS=Context The callback id used when calling back into JavaScript.
- * @return True if the action was valid.
- * @throws JSONException
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- if (action.equals("start")) {
- this.start();
- }
- else if (action.equals("stop")) {
- this.stop();
- }
- else if (action.equals("getStatus")) {
- int i = this.getStatus();
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, i));
- }
- else if (action.equals("getHeading")) {
- // If not running, then this is an async call, so don't worry about waiting
- if (this.status != CompassListener.RUNNING) {
- int r = this.start();
- if (r == CompassListener.ERROR_FAILED_TO_START) {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, CompassListener.ERROR_FAILED_TO_START));
- return true;
- }
- // Set a timeout callback on the main thread.
- Handler handler = new Handler(Looper.getMainLooper());
- handler.postDelayed(new Runnable() {
- public void run() {
- CompassListener.this.timeout();
- }
- }, 2000);
- }
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, getCompassHeading()));
- }
- else if (action.equals("setTimeout")) {
- this.setTimeout(args.getLong(0));
- }
- else if (action.equals("getTimeout")) {
- long l = this.getTimeout();
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, l));
- } else {
- // Unsupported action
- return false;
- }
- return true;
- }
-
- /**
- * Called when listener is to be shut down and object is being destroyed.
- */
- public void onDestroy() {
- this.stop();
- }
-
- /**
- * Called when app has navigated and JS listeners have been destroyed.
- */
- public void onReset() {
- 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 compass sensor from sensor manager
- @SuppressWarnings("deprecation")
- List list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
-
- // 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_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
- }
-
- /**
- * Called after a delay to time out if the listener has not attached fast enough.
- */
- private void timeout() {
- if (this.status == CompassListener.STARTING) {
- this.setStatus(CompassListener.ERROR_FAILED_TO_START);
- if (this.callbackContext != null) {
- this.callbackContext.error("Compass listener failed to start.");
- }
- }
- }
-
- /**
- * 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() throws JSONException {
- JSONObject obj = new JSONObject();
-
- 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);
-
- return obj;
- }
-
-}
diff --git a/framework/src/org/apache/cordova/ContactAccessor.java b/framework/src/org/apache/cordova/ContactAccessor.java
deleted file mode 100644
index 04b43420..00000000
--- a/framework/src/org/apache/cordova/ContactAccessor.java
+++ /dev/null
@@ -1,198 +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 org.apache.cordova;
-
-import java.util.HashMap;
-
-import android.util.Log;
-import android.webkit.WebView;
-
-import org.apache.cordova.api.CordovaInterface;
-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 CordovaInterface 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 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 buildPopulationSet(JSONArray fields) {
- HashMap map = new HashMap();
-
- 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
- * This implementation has several advantages:
- *
- * - It sees contacts from multiple accounts.
- *
- It works with aggregated contacts. So for example, if the contact is the result
- * of aggregation of two raw contacts from different accounts, it may return the name from
- * one and the phone number from the other.
- *
- It is efficient because it uses the more efficient current API.
- *
- Not obvious in this particular example, but it has access to new kinds
- * of data available exclusively through the new APIs. Exercise for the reader: add support
- * for nickname (see {@link android.provider.ContactsContract.CommonDataKinds.Nickname}) or
- * social status updates (see {@link android.provider.ContactsContract.StatusUpdates}).
- *
- */
-
-public class ContactAccessorSdk5 extends ContactAccessor {
-
- /**
- * Keep the photo size under the 1 MB blog limit.
- */
- private static final long MAX_PHOTO_SIZE = 1048576;
-
- private static final String EMAIL_REGEXP = ".+@.+\\.+.+"; /* @.*/
-
- /**
- * A static map that converts the JavaScript property name to Android database column name.
- */
- private static final Map dbMap = new HashMap();
- static {
- dbMap.put("id", ContactsContract.Data.CONTACT_ID);
- dbMap.put("displayName", ContactsContract.Contacts.DISPLAY_NAME);
- dbMap.put("name", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
- dbMap.put("name.formatted", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
- dbMap.put("name.familyName", ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
- dbMap.put("name.givenName", ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
- dbMap.put("name.middleName", ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME);
- dbMap.put("name.honorificPrefix", ContactsContract.CommonDataKinds.StructuredName.PREFIX);
- dbMap.put("name.honorificSuffix", ContactsContract.CommonDataKinds.StructuredName.SUFFIX);
- dbMap.put("nickname", ContactsContract.CommonDataKinds.Nickname.NAME);
- dbMap.put("phoneNumbers", ContactsContract.CommonDataKinds.Phone.NUMBER);
- dbMap.put("phoneNumbers.value", ContactsContract.CommonDataKinds.Phone.NUMBER);
- dbMap.put("emails", ContactsContract.CommonDataKinds.Email.DATA);
- dbMap.put("emails.value", ContactsContract.CommonDataKinds.Email.DATA);
- dbMap.put("addresses", ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS);
- dbMap.put("addresses.formatted", ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS);
- dbMap.put("addresses.streetAddress", ContactsContract.CommonDataKinds.StructuredPostal.STREET);
- dbMap.put("addresses.locality", ContactsContract.CommonDataKinds.StructuredPostal.CITY);
- dbMap.put("addresses.region", ContactsContract.CommonDataKinds.StructuredPostal.REGION);
- dbMap.put("addresses.postalCode", ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE);
- dbMap.put("addresses.country", ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY);
- dbMap.put("ims", ContactsContract.CommonDataKinds.Im.DATA);
- dbMap.put("ims.value", ContactsContract.CommonDataKinds.Im.DATA);
- dbMap.put("organizations", ContactsContract.CommonDataKinds.Organization.COMPANY);
- dbMap.put("organizations.name", ContactsContract.CommonDataKinds.Organization.COMPANY);
- dbMap.put("organizations.department", ContactsContract.CommonDataKinds.Organization.DEPARTMENT);
- dbMap.put("organizations.title", ContactsContract.CommonDataKinds.Organization.TITLE);
- dbMap.put("birthday", ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
- dbMap.put("note", ContactsContract.CommonDataKinds.Note.NOTE);
- dbMap.put("photos.value", ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
- //dbMap.put("categories.value", null);
- dbMap.put("urls", ContactsContract.CommonDataKinds.Website.URL);
- dbMap.put("urls.value", ContactsContract.CommonDataKinds.Website.URL);
- }
-
- /**
- * Create an contact accessor.
- */
- public ContactAccessorSdk5(WebView view, CordovaInterface context) {
- mApp = context;
- mView = view;
- }
-
- /**
- * This method takes the fields required and search options in order to produce an
- * array of contacts that matches the criteria provided.
- * @param fields an array of items to be used as search criteria
- * @param options that can be applied to contact searching
- * @return an array of contacts
- */
- @Override
- public JSONArray search(JSONArray fields, JSONObject options) {
- // Get the find options
- String searchTerm = "";
- int limit = Integer.MAX_VALUE;
- boolean multiple = true;
-
- if (options != null) {
- searchTerm = options.optString("filter");
- if (searchTerm.length() == 0) {
- searchTerm = "%";
- }
- else {
- searchTerm = "%" + searchTerm + "%";
- }
-
- try {
- multiple = options.getBoolean("multiple");
- if (!multiple) {
- limit = 1;
- }
- } catch (JSONException e) {
- // Multiple was not specified so we assume the default is true.
- }
- }
- else {
- searchTerm = "%";
- }
-
-
- //Log.d(LOG_TAG, "Search Term = " + searchTerm);
- //Log.d(LOG_TAG, "Field Length = " + fields.length());
- //Log.d(LOG_TAG, "Fields = " + fields.toString());
-
- // Loop through the fields the user provided to see what data should be returned.
- HashMap populate = buildPopulationSet(fields);
-
- // Build the ugly where clause and where arguments for one big query.
- WhereOptions whereOptions = buildWhereClause(fields, searchTerm);
-
- // Get all the id's where the search term matches the fields passed in.
- Cursor idCursor = mApp.getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI,
- new String[] { ContactsContract.Data.CONTACT_ID },
- whereOptions.getWhere(),
- whereOptions.getWhereArgs(),
- ContactsContract.Data.CONTACT_ID + " ASC");
-
- // Create a set of unique ids
- Set contactIds = new HashSet();
- int idColumn = -1;
- while (idCursor.moveToNext()) {
- if (idColumn < 0) {
- idColumn = idCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID);
- }
- contactIds.add(idCursor.getString(idColumn));
- }
- idCursor.close();
-
- // Build a query that only looks at ids
- WhereOptions idOptions = buildIdClause(contactIds, searchTerm);
-
- // Determine which columns we should be fetching.
- HashSet columnsToFetch = new HashSet();
- columnsToFetch.add(ContactsContract.Data.CONTACT_ID);
- columnsToFetch.add(ContactsContract.Data.RAW_CONTACT_ID);
- columnsToFetch.add(ContactsContract.Data.MIMETYPE);
-
- if (isRequired("displayName", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
- }
- if (isRequired("name", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.PREFIX);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.SUFFIX);
- }
- if (isRequired("phoneNumbers", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.Phone._ID);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Phone.NUMBER);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Phone.TYPE);
- }
- if (isRequired("emails", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.Email._ID);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Email.DATA);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Email.TYPE);
- }
- if (isRequired("addresses", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal._ID);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.TYPE);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.STREET);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.CITY);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.REGION);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE);
- columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY);
- }
- if (isRequired("organizations", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.Organization._ID);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.TYPE);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.DEPARTMENT);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.COMPANY);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.TITLE);
- }
- if (isRequired("ims", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.Im._ID);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Im.DATA);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Im.TYPE);
- }
- if (isRequired("note", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.Note.NOTE);
- }
- if (isRequired("nickname", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.Nickname.NAME);
- }
- if (isRequired("urls", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.Website._ID);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Website.URL);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Website.TYPE);
- }
- if (isRequired("birthday", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.Event.START_DATE);
- columnsToFetch.add(ContactsContract.CommonDataKinds.Event.TYPE);
- }
- if (isRequired("photos", populate)) {
- columnsToFetch.add(ContactsContract.CommonDataKinds.Photo._ID);
- }
-
- // Do the id query
- Cursor c = mApp.getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI,
- columnsToFetch.toArray(new String[] {}),
- idOptions.getWhere(),
- idOptions.getWhereArgs(),
- ContactsContract.Data.CONTACT_ID + " ASC");
-
- JSONArray contacts = populateContactArray(limit, populate, c);
- return contacts;
- }
-
- /**
- * A special search that finds one contact by id
- *
- * @param id contact to find by id
- * @return a JSONObject representing the contact
- * @throws JSONException
- */
- public JSONObject getContactById(String id) throws JSONException {
- // Do the id query
- Cursor c = mApp.getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI,
- null,
- ContactsContract.Data.CONTACT_ID + " = ? ",
- new String[] { id },
- ContactsContract.Data.CONTACT_ID + " ASC");
-
- JSONArray fields = new JSONArray();
- fields.put("*");
-
- HashMap populate = buildPopulationSet(fields);
-
- JSONArray contacts = populateContactArray(1, populate, c);
-
- if (contacts.length() == 1) {
- return contacts.getJSONObject(0);
- } else {
- return null;
- }
- }
-
- /**
- * Creates an array of contacts from the cursor you pass in
- *
- * @param limit max number of contacts for the array
- * @param populate whether or not you should populate a certain value
- * @param c the cursor
- * @return a JSONArray of contacts
- */
- private JSONArray populateContactArray(int limit,
- HashMap populate, Cursor c) {
-
- String contactId = "";
- String rawId = "";
- String oldContactId = "";
- boolean newContact = true;
- String mimetype = "";
-
- JSONArray contacts = new JSONArray();
- JSONObject contact = new JSONObject();
- JSONArray organizations = new JSONArray();
- JSONArray addresses = new JSONArray();
- JSONArray phones = new JSONArray();
- JSONArray emails = new JSONArray();
- JSONArray ims = new JSONArray();
- JSONArray websites = new JSONArray();
- JSONArray photos = new JSONArray();
-
- // Column indices
- int colContactId = c.getColumnIndex(ContactsContract.Data.CONTACT_ID);
- int colRawContactId = c.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID);
- int colMimetype = c.getColumnIndex(ContactsContract.Data.MIMETYPE);
- int colDisplayName = c.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
- int colNote = c.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE);
- int colNickname = c.getColumnIndex(ContactsContract.CommonDataKinds.Nickname.NAME);
- int colBirthday = c.getColumnIndex(ContactsContract.CommonDataKinds.Event.START_DATE);
- int colEventType = c.getColumnIndex(ContactsContract.CommonDataKinds.Event.TYPE);
-
- if (c.getCount() > 0) {
- while (c.moveToNext() && (contacts.length() <= (limit - 1))) {
- try {
- contactId = c.getString(colContactId);
- rawId = c.getString(colRawContactId);
-
- // If we are in the first row set the oldContactId
- if (c.getPosition() == 0) {
- oldContactId = contactId;
- }
-
- // When the contact ID changes we need to push the Contact object
- // to the array of contacts and create new objects.
- if (!oldContactId.equals(contactId)) {
- // Populate the Contact object with it's arrays
- // and push the contact into the contacts array
- contacts.put(populateContact(contact, organizations, addresses, phones,
- emails, ims, websites, photos));
-
- // Clean up the objects
- contact = new JSONObject();
- organizations = new JSONArray();
- addresses = new JSONArray();
- phones = new JSONArray();
- emails = new JSONArray();
- ims = new JSONArray();
- websites = new JSONArray();
- photos = new JSONArray();
-
- // Set newContact to true as we are starting to populate a new contact
- newContact = true;
- }
-
- // When we detect a new contact set the ID and display name.
- // These fields are available in every row in the result set returned.
- if (newContact) {
- newContact = false;
- contact.put("id", contactId);
- contact.put("rawId", rawId);
- }
-
- // Grab the mimetype of the current row as it will be used in a lot of comparisons
- mimetype = c.getString(colMimetype);
-
- if (mimetype.equals(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)) {
- contact.put("displayName", c.getString(colDisplayName));
- }
-
- if (mimetype.equals(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
- && isRequired("name", populate)) {
- contact.put("name", nameQuery(c));
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
- && isRequired("phoneNumbers", populate)) {
- phones.put(phoneQuery(c));
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
- && isRequired("emails", populate)) {
- emails.put(emailQuery(c));
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
- && isRequired("addresses", populate)) {
- addresses.put(addressQuery(c));
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
- && isRequired("organizations", populate)) {
- organizations.put(organizationQuery(c));
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
- && isRequired("ims", populate)) {
- ims.put(imQuery(c));
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE)
- && isRequired("note", populate)) {
- contact.put("note", c.getString(colNote));
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE)
- && isRequired("nickname", populate)) {
- contact.put("nickname", c.getString(colNickname));
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE)
- && isRequired("urls", populate)) {
- websites.put(websiteQuery(c));
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE)) {
- if (isRequired("birthday", populate) &&
- ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY == c.getInt(colEventType)) {
- contact.put("birthday", c.getString(colBirthday));
- }
- }
- else if (mimetype.equals(ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
- && isRequired("photos", populate)) {
- photos.put(photoQuery(c, contactId));
- }
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
-
- // Set the old contact ID
- oldContactId = contactId;
-
- }
-
- // Push the last contact into the contacts array
- if (contacts.length() < limit) {
- contacts.put(populateContact(contact, organizations, addresses, phones,
- emails, ims, websites, photos));
- }
- }
- c.close();
- return contacts;
- }
-
- /**
- * Builds a where clause all all the ids passed into the method
- * @param contactIds a set of unique contact ids
- * @param searchTerm what to search for
- * @return an object containing the selection and selection args
- */
- private WhereOptions buildIdClause(Set contactIds, String searchTerm) {
- WhereOptions options = new WhereOptions();
-
- // If the user is searching for every contact then short circuit the method
- // and return a shorter where clause to be searched.
- if (searchTerm.equals("%")) {
- options.setWhere("(" + ContactsContract.Data.CONTACT_ID + " LIKE ? )");
- options.setWhereArgs(new String[] { searchTerm });
- return options;
- }
-
- // This clause means that there are specific ID's to be populated
- Iterator it = contactIds.iterator();
- StringBuffer buffer = new StringBuffer("(");
-
- while (it.hasNext()) {
- buffer.append("'" + it.next() + "'");
- if (it.hasNext()) {
- buffer.append(",");
- }
- }
- buffer.append(")");
-
- options.setWhere(ContactsContract.Data.CONTACT_ID + " IN " + buffer.toString());
- options.setWhereArgs(null);
-
- return options;
- }
-
- /**
- * Create a new contact using a JSONObject to hold all the data.
- * @param contact
- * @param organizations array of organizations
- * @param addresses array of addresses
- * @param phones array of phones
- * @param emails array of emails
- * @param ims array of instant messenger addresses
- * @param websites array of websites
- * @param photos
- * @return
- */
- private JSONObject populateContact(JSONObject contact, JSONArray organizations,
- JSONArray addresses, JSONArray phones, JSONArray emails,
- JSONArray ims, JSONArray websites, JSONArray photos) {
- try {
- // Only return the array if it has at least one entry
- if (organizations.length() > 0) {
- contact.put("organizations", organizations);
- }
- if (addresses.length() > 0) {
- contact.put("addresses", addresses);
- }
- if (phones.length() > 0) {
- contact.put("phoneNumbers", phones);
- }
- if (emails.length() > 0) {
- contact.put("emails", emails);
- }
- if (ims.length() > 0) {
- contact.put("ims", ims);
- }
- if (websites.length() > 0) {
- contact.put("urls", websites);
- }
- if (photos.length() > 0) {
- contact.put("photos", photos);
- }
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return contact;
- }
-
- /**
- * Take the search criteria passed into the method and create a SQL WHERE clause.
- * @param fields the properties to search against
- * @param searchTerm the string to search for
- * @return an object containing the selection and selection args
- */
- private WhereOptions buildWhereClause(JSONArray fields, String searchTerm) {
-
- ArrayList where = new ArrayList();
- ArrayList whereArgs = new ArrayList();
-
- WhereOptions options = new WhereOptions();
-
- /*
- * Special case where the user wants all fields returned
- */
- if (isWildCardSearch(fields)) {
- // Get all contacts with all properties
- if ("%".equals(searchTerm)) {
- options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )");
- options.setWhereArgs(new String[] { searchTerm });
- return options;
- } else {
- // Get all contacts that match the filter but return all properties
- where.add("(" + dbMap.get("displayName") + " LIKE ? )");
- whereArgs.add(searchTerm);
- where.add("(" + dbMap.get("name") + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
- where.add("(" + dbMap.get("nickname") + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE);
- where.add("(" + dbMap.get("phoneNumbers") + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
- where.add("(" + dbMap.get("emails") + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
- where.add("(" + dbMap.get("addresses") + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
- where.add("(" + dbMap.get("ims") + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE);
- where.add("(" + dbMap.get("organizations") + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
- where.add("(" + dbMap.get("note") + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
- where.add("(" + dbMap.get("urls") + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
- }
- }
-
- /*
- * Special case for when the user wants all the contacts but
- */
- if ("%".equals(searchTerm)) {
- options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )");
- options.setWhereArgs(new String[] { searchTerm });
- return options;
- }
-
- String key;
- try {
- //Log.d(LOG_TAG, "How many fields do we have = " + fields.length());
- for (int i = 0; i < fields.length(); i++) {
- key = fields.getString(i);
-
- if (key.equals("id")) {
- where.add("(" + dbMap.get(key) + " = ? )");
- whereArgs.add(searchTerm.substring(1, searchTerm.length() - 1));
- }
- else if (key.startsWith("displayName")) {
- where.add("(" + dbMap.get(key) + " LIKE ? )");
- whereArgs.add(searchTerm);
- }
- else if (key.startsWith("name")) {
- where.add("(" + dbMap.get(key) + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
- }
- else if (key.startsWith("nickname")) {
- where.add("(" + dbMap.get(key) + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE);
- }
- else if (key.startsWith("phoneNumbers")) {
- where.add("(" + dbMap.get(key) + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
- }
- else if (key.startsWith("emails")) {
- where.add("(" + dbMap.get(key) + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
- }
- else if (key.startsWith("addresses")) {
- where.add("(" + dbMap.get(key) + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
- }
- else if (key.startsWith("ims")) {
- where.add("(" + dbMap.get(key) + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE);
- }
- else if (key.startsWith("organizations")) {
- where.add("(" + dbMap.get(key) + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
- }
- // else if (key.startsWith("birthday")) {
-// where.add("(" + dbMap.get(key) + " LIKE ? AND "
-// + ContactsContract.Data.MIMETYPE + " = ? )");
-// }
- else if (key.startsWith("note")) {
- where.add("(" + dbMap.get(key) + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
- }
- else if (key.startsWith("urls")) {
- where.add("(" + dbMap.get(key) + " LIKE ? AND "
- + ContactsContract.Data.MIMETYPE + " = ? )");
- whereArgs.add(searchTerm);
- whereArgs.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
- }
- }
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
-
- // Creating the where string
- StringBuffer selection = new StringBuffer();
- for (int i = 0; i < where.size(); i++) {
- selection.append(where.get(i));
- if (i != (where.size() - 1)) {
- selection.append(" OR ");
- }
- }
- options.setWhere(selection.toString());
-
- // Creating the where args array
- String[] selectionArgs = new String[whereArgs.size()];
- for (int i = 0; i < whereArgs.size(); i++) {
- selectionArgs[i] = whereArgs.get(i);
- }
- options.setWhereArgs(selectionArgs);
-
- return options;
- }
-
- /**
- * If the user passes in the '*' wildcard character for search then they want all fields for each contact
- *
- * @param fields
- * @return true if wildcard search requested, false otherwise
- */
- private boolean isWildCardSearch(JSONArray fields) {
- // Only do a wildcard search if we are passed ["*"]
- if (fields.length() == 1) {
- try {
- if ("*".equals(fields.getString(0))) {
- return true;
- }
- } catch (JSONException e) {
- return false;
- }
- }
- return false;
- }
-
- /**
- * Create a ContactOrganization JSONObject
- * @param cursor the current database row
- * @return a JSONObject representing a ContactOrganization
- */
- private JSONObject organizationQuery(Cursor cursor) {
- JSONObject organization = new JSONObject();
- try {
- organization.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization._ID)));
- organization.put("pref", false); // Android does not store pref attribute
- organization.put("type", getOrgType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE))));
- organization.put("department", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DEPARTMENT)));
- organization.put("name", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.COMPANY)));
- organization.put("title", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE)));
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return organization;
- }
-
- /**
- * Create a ContactAddress JSONObject
- * @param cursor the current database row
- * @return a JSONObject representing a ContactAddress
- */
- private JSONObject addressQuery(Cursor cursor) {
- JSONObject address = new JSONObject();
- try {
- address.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal._ID)));
- address.put("pref", false); // Android does not store pref attribute
- address.put("type", getAddressType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE))));
- address.put("formatted", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS)));
- address.put("streetAddress", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)));
- address.put("locality", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)));
- address.put("region", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION)));
- address.put("postalCode", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)));
- address.put("country", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)));
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return address;
- }
-
- /**
- * Create a ContactName JSONObject
- * @param cursor the current database row
- * @return a JSONObject representing a ContactName
- */
- private JSONObject nameQuery(Cursor cursor) {
- JSONObject contactName = new JSONObject();
- try {
- String familyName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
- String givenName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
- String middleName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME));
- String honorificPrefix = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.PREFIX));
- String honorificSuffix = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.SUFFIX));
-
- // Create the formatted name
- StringBuffer formatted = new StringBuffer("");
- if (honorificPrefix != null) {
- formatted.append(honorificPrefix + " ");
- }
- if (givenName != null) {
- formatted.append(givenName + " ");
- }
- if (middleName != null) {
- formatted.append(middleName + " ");
- }
- if (familyName != null) {
- formatted.append(familyName);
- }
- if (honorificSuffix != null) {
- formatted.append(" " + honorificSuffix);
- }
-
- contactName.put("familyName", familyName);
- contactName.put("givenName", givenName);
- contactName.put("middleName", middleName);
- contactName.put("honorificPrefix", honorificPrefix);
- contactName.put("honorificSuffix", honorificSuffix);
- contactName.put("formatted", formatted);
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return contactName;
- }
-
- /**
- * Create a ContactField JSONObject
- * @param cursor the current database row
- * @return a JSONObject representing a ContactField
- */
- private JSONObject phoneQuery(Cursor cursor) {
- JSONObject phoneNumber = new JSONObject();
- try {
- phoneNumber.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID)));
- phoneNumber.put("pref", false); // Android does not store pref attribute
- phoneNumber.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
- phoneNumber.put("type", getPhoneType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE))));
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- } catch (Exception excp) {
- Log.e(LOG_TAG, excp.getMessage(), excp);
- }
- return phoneNumber;
- }
-
- /**
- * Create a ContactField JSONObject
- * @param cursor the current database row
- * @return a JSONObject representing a ContactField
- */
- private JSONObject emailQuery(Cursor cursor) {
- JSONObject email = new JSONObject();
- try {
- email.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email._ID)));
- email.put("pref", false); // Android does not store pref attribute
- email.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)));
- email.put("type", getContactType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE))));
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return email;
- }
-
- /**
- * Create a ContactField JSONObject
- * @param cursor the current database row
- * @return a JSONObject representing a ContactField
- */
- private JSONObject imQuery(Cursor cursor) {
- JSONObject im = new JSONObject();
- try {
- im.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im._ID)));
- im.put("pref", false); // Android does not store pref attribute
- im.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)));
- im.put("type", getImType(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.PROTOCOL))));
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return im;
- }
-
- /**
- * Create a ContactField JSONObject
- * @param cursor the current database row
- * @return a JSONObject representing a ContactField
- */
- private JSONObject websiteQuery(Cursor cursor) {
- JSONObject website = new JSONObject();
- try {
- website.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website._ID)));
- website.put("pref", false); // Android does not store pref attribute
- website.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website.URL)));
- website.put("type", getContactType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website.TYPE))));
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return website;
- }
-
- /**
- * Create a ContactField JSONObject
- * @param contactId
- * @return a JSONObject representing a ContactField
- */
- private JSONObject photoQuery(Cursor cursor, String contactId) {
- JSONObject photo = new JSONObject();
- try {
- photo.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo._ID)));
- photo.put("pref", false);
- photo.put("type", "url");
- Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, (new Long(contactId)));
- Uri photoUri = Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
- photo.put("value", photoUri.toString());
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return photo;
- }
-
- @Override
- /**
- * This method will save a contact object into the devices contacts database.
- *
- * @param contact the contact to be saved.
- * @returns the id if the contact is successfully saved, null otherwise.
- */
- public String save(JSONObject contact) {
- AccountManager mgr = AccountManager.get(mApp.getActivity());
- Account[] accounts = mgr.getAccounts();
- String accountName = null;
- String accountType = null;
-
- if (accounts.length == 1) {
- accountName = accounts[0].name;
- accountType = accounts[0].type;
- }
- else if (accounts.length > 1) {
- for (Account a : accounts) {
- if (a.type.contains("eas") && a.name.matches(EMAIL_REGEXP)) /*Exchange ActiveSync*/{
- accountName = a.name;
- accountType = a.type;
- break;
- }
- }
- if (accountName == null) {
- for (Account a : accounts) {
- if (a.type.contains("com.google") && a.name.matches(EMAIL_REGEXP)) /*Google sync provider*/{
- accountName = a.name;
- accountType = a.type;
- break;
- }
- }
- }
- if (accountName == null) {
- for (Account a : accounts) {
- if (a.name.matches(EMAIL_REGEXP)) /*Last resort, just look for an email address...*/{
- accountName = a.name;
- accountType = a.type;
- break;
- }
- }
- }
- }
-
- String id = getJsonString(contact, "id");
- // Create new contact
- if (id == null) {
- return createNewContact(contact, accountType, accountName);
- }
- // Modify existing contact
- else {
- return modifyContact(id, contact, accountType, accountName);
- }
- }
-
- /**
- * Creates a new contact and stores it in the database
- *
- * @param id the raw contact id which is required for linking items to the contact
- * @param contact the contact to be saved
- * @param account the account to be saved under
- */
- private String modifyContact(String id, JSONObject contact, String accountType, String accountName) {
- // Get the RAW_CONTACT_ID which is needed to insert new values in an already existing contact.
- // But not needed to update existing values.
- int rawId = (new Integer(getJsonString(contact, "rawId"))).intValue();
-
- // Create a list of attributes to add to the contact database
- ArrayList ops = new ArrayList();
-
- //Add contact type
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.RawContacts.CONTENT_URI)
- .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
- .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
- .build());
-
- // Modify name
- JSONObject name;
- try {
- String displayName = getJsonString(contact, "displayName");
- name = contact.getJSONObject("name");
- if (displayName != null || name != null) {
- ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { id, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE });
-
- if (displayName != null) {
- builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName);
- }
-
- String familyName = getJsonString(name, "familyName");
- if (familyName != null) {
- builder.withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, familyName);
- }
- String middleName = getJsonString(name, "middleName");
- if (middleName != null) {
- builder.withValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, middleName);
- }
- String givenName = getJsonString(name, "givenName");
- if (givenName != null) {
- builder.withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, givenName);
- }
- String honorificPrefix = getJsonString(name, "honorificPrefix");
- if (honorificPrefix != null) {
- builder.withValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX, honorificPrefix);
- }
- String honorificSuffix = getJsonString(name, "honorificSuffix");
- if (honorificSuffix != null) {
- builder.withValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, honorificSuffix);
- }
-
- ops.add(builder.build());
- }
- } catch (JSONException e1) {
- Log.d(LOG_TAG, "Could not get name");
- }
-
- // Modify phone numbers
- JSONArray phones = null;
- try {
- phones = contact.getJSONArray("phoneNumbers");
- if (phones != null) {
- // Delete all the phones
- if (phones.length() == 0) {
- ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { "" + rawId, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE })
- .build());
- }
- // Modify or add a phone
- else {
- for (int i = 0; i < phones.length(); i++) {
- JSONObject phone = (JSONObject) phones.get(i);
- String phoneId = getJsonString(phone, "id");
- // This is a new phone so do a DB insert
- if (phoneId == null) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
- contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
- contentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, getJsonString(phone, "value"));
- contentValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, getPhoneType(getJsonString(phone, "type")));
-
- ops.add(ContentProviderOperation.newInsert(
- ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
- }
- // This is an existing phone so do a DB update
- else {
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.CommonDataKinds.Phone._ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { phoneId, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE })
- .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, getJsonString(phone, "value"))
- .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, getPhoneType(getJsonString(phone, "type")))
- .build());
- }
- }
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get phone numbers");
- }
-
- // Modify emails
- JSONArray emails = null;
- try {
- emails = contact.getJSONArray("emails");
- if (emails != null) {
- // Delete all the emails
- if (emails.length() == 0) {
- ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { "" + rawId, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE })
- .build());
- }
- // Modify or add a email
- else {
- for (int i = 0; i < emails.length(); i++) {
- JSONObject email = (JSONObject) emails.get(i);
- String emailId = getJsonString(email, "id");
- // This is a new email so do a DB insert
- if (emailId == null) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
- contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
- contentValues.put(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value"));
- contentValues.put(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type")));
-
- ops.add(ContentProviderOperation.newInsert(
- ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
- }
- // This is an existing email so do a DB update
- else {
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.CommonDataKinds.Email._ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { emailId, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE })
- .withValue(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value"))
- .withValue(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type")))
- .build());
- }
- }
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get emails");
- }
-
- // Modify addresses
- JSONArray addresses = null;
- try {
- addresses = contact.getJSONArray("addresses");
- if (addresses != null) {
- // Delete all the addresses
- if (addresses.length() == 0) {
- ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { "" + rawId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE })
- .build());
- }
- // Modify or add a address
- else {
- for (int i = 0; i < addresses.length(); i++) {
- JSONObject address = (JSONObject) addresses.get(i);
- String addressId = getJsonString(address, "id");
- // This is a new address so do a DB insert
- if (addressId == null) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
- contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
- contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")));
- contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"));
- contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"));
- contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"));
- contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.REGION, getJsonString(address, "region"));
- contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, getJsonString(address, "postalCode"));
- contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, getJsonString(address, "country"));
-
- ops.add(ContentProviderOperation.newInsert(
- ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
- }
- // This is an existing address so do a DB update
- else {
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.CommonDataKinds.StructuredPostal._ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { addressId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE })
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.REGION, getJsonString(address, "region"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, getJsonString(address, "postalCode"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, getJsonString(address, "country"))
- .build());
- }
- }
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get addresses");
- }
-
- // Modify organizations
- JSONArray organizations = null;
- try {
- organizations = contact.getJSONArray("organizations");
- if (organizations != null) {
- // Delete all the organizations
- if (organizations.length() == 0) {
- ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { "" + rawId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE })
- .build());
- }
- // Modify or add a organization
- else {
- for (int i = 0; i < organizations.length(); i++) {
- JSONObject org = (JSONObject) organizations.get(i);
- String orgId = getJsonString(org, "id");
- // This is a new organization so do a DB insert
- if (orgId == null) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
- contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
- contentValues.put(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")));
- contentValues.put(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"));
- contentValues.put(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"));
- contentValues.put(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"));
-
- ops.add(ContentProviderOperation.newInsert(
- ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
- }
- // This is an existing organization so do a DB update
- else {
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.CommonDataKinds.Organization._ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { orgId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE })
- .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")))
- .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"))
- .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"))
- .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"))
- .build());
- }
- }
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get organizations");
- }
-
- // Modify IMs
- JSONArray ims = null;
- try {
- ims = contact.getJSONArray("ims");
- if (ims != null) {
- // Delete all the ims
- if (ims.length() == 0) {
- ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { "" + rawId, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE })
- .build());
- }
- // Modify or add a im
- else {
- for (int i = 0; i < ims.length(); i++) {
- JSONObject im = (JSONObject) ims.get(i);
- String imId = getJsonString(im, "id");
- // This is a new IM so do a DB insert
- if (imId == null) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
- contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE);
- contentValues.put(ContactsContract.CommonDataKinds.Im.DATA, getJsonString(im, "value"));
- contentValues.put(ContactsContract.CommonDataKinds.Im.TYPE, getImType(getJsonString(im, "type")));
-
- ops.add(ContentProviderOperation.newInsert(
- ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
- }
- // This is an existing IM so do a DB update
- else {
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.CommonDataKinds.Im._ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { imId, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE })
- .withValue(ContactsContract.CommonDataKinds.Im.DATA, getJsonString(im, "value"))
- .withValue(ContactsContract.CommonDataKinds.Im.TYPE, getContactType(getJsonString(im, "type")))
- .build());
- }
- }
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get emails");
- }
-
- // Modify note
- String note = getJsonString(contact, "note");
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { id, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE })
- .withValue(ContactsContract.CommonDataKinds.Note.NOTE, note)
- .build());
-
- // Modify nickname
- String nickname = getJsonString(contact, "nickname");
- if (nickname != null) {
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { id, ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE })
- .withValue(ContactsContract.CommonDataKinds.Nickname.NAME, nickname)
- .build());
- }
-
- // Modify urls
- JSONArray websites = null;
- try {
- websites = contact.getJSONArray("urls");
- if (websites != null) {
- // Delete all the websites
- if (websites.length() == 0) {
- Log.d(LOG_TAG, "This means we should be deleting all the phone numbers.");
- ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { "" + rawId, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE })
- .build());
- }
- // Modify or add a website
- else {
- for (int i = 0; i < websites.length(); i++) {
- JSONObject website = (JSONObject) websites.get(i);
- String websiteId = getJsonString(website, "id");
- // This is a new website so do a DB insert
- if (websiteId == null) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
- contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
- contentValues.put(ContactsContract.CommonDataKinds.Website.DATA, getJsonString(website, "value"));
- contentValues.put(ContactsContract.CommonDataKinds.Website.TYPE, getContactType(getJsonString(website, "type")));
-
- ops.add(ContentProviderOperation.newInsert(
- ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
- }
- // This is an existing website so do a DB update
- else {
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.CommonDataKinds.Website._ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { websiteId, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE })
- .withValue(ContactsContract.CommonDataKinds.Website.DATA, getJsonString(website, "value"))
- .withValue(ContactsContract.CommonDataKinds.Website.TYPE, getContactType(getJsonString(website, "type")))
- .build());
- }
- }
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get websites");
- }
-
- // Modify birthday
- String birthday = getJsonString(contact, "birthday");
- if (birthday != null) {
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=? AND " +
- ContactsContract.CommonDataKinds.Event.TYPE + "=?",
- new String[] { id, ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, new String("" + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) })
- .withValue(ContactsContract.CommonDataKinds.Event.TYPE, ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY)
- .withValue(ContactsContract.CommonDataKinds.Event.START_DATE, birthday)
- .build());
- }
-
- // Modify photos
- JSONArray photos = null;
- try {
- photos = contact.getJSONArray("photos");
- if (photos != null) {
- // Delete all the photos
- if (photos.length() == 0) {
- ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { "" + rawId, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE })
- .build());
- }
- // Modify or add a photo
- else {
- for (int i = 0; i < photos.length(); i++) {
- JSONObject photo = (JSONObject) photos.get(i);
- String photoId = getJsonString(photo, "id");
- byte[] bytes = getPhotoBytes(getJsonString(photo, "value"));
- // This is a new photo so do a DB insert
- if (photoId == null) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
- contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
- contentValues.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
- contentValues.put(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes);
-
- ops.add(ContentProviderOperation.newInsert(
- ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
- }
- // This is an existing photo so do a DB update
- else {
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(ContactsContract.CommonDataKinds.Photo._ID + "=? AND " +
- ContactsContract.Data.MIMETYPE + "=?",
- new String[] { photoId, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE })
- .withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1)
- .withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes)
- .build());
- }
- }
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get photos");
- }
-
- boolean retVal = true;
-
- //Modify contact
- try {
- mApp.getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- Log.e(LOG_TAG, Log.getStackTraceString(e), e);
- retVal = false;
- } catch (OperationApplicationException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- Log.e(LOG_TAG, Log.getStackTraceString(e), e);
- retVal = false;
- }
-
- // if the save was a success return the contact ID
- if (retVal) {
- return id;
- } else {
- return null;
- }
- }
-
- /**
- * Add a website to a list of database actions to be performed
- *
- * @param ops the list of database actions
- * @param website the item to be inserted
- */
- private void insertWebsite(ArrayList ops,
- JSONObject website) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Website.DATA, getJsonString(website, "value"))
- .withValue(ContactsContract.CommonDataKinds.Website.TYPE, getContactType(getJsonString(website, "type")))
- .build());
- }
-
- /**
- * Add an im to a list of database actions to be performed
- *
- * @param ops the list of database actions
- * @param im the item to be inserted
- */
- private void insertIm(ArrayList ops, JSONObject im) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Im.DATA, getJsonString(im, "value"))
- .withValue(ContactsContract.CommonDataKinds.Im.TYPE, getImType(getJsonString(im, "type")))
- .build());
- }
-
- /**
- * Add an organization to a list of database actions to be performed
- *
- * @param ops the list of database actions
- * @param org the item to be inserted
- */
- private void insertOrganization(ArrayList ops,
- JSONObject org) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")))
- .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"))
- .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"))
- .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"))
- .build());
- }
-
- /**
- * Add an address to a list of database actions to be performed
- *
- * @param ops the list of database actions
- * @param address the item to be inserted
- */
- private void insertAddress(ArrayList ops,
- JSONObject address) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.REGION, getJsonString(address, "region"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, getJsonString(address, "postalCode"))
- .withValue(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, getJsonString(address, "country"))
- .build());
- }
-
- /**
- * Add an email to a list of database actions to be performed
- *
- * @param ops the list of database actions
- * @param email the item to be inserted
- */
- private void insertEmail(ArrayList ops,
- JSONObject email) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value"))
- .withValue(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type")))
- .build());
- }
-
- /**
- * Add a phone to a list of database actions to be performed
- *
- * @param ops the list of database actions
- * @param phone the item to be inserted
- */
- private void insertPhone(ArrayList ops,
- JSONObject phone) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, getJsonString(phone, "value"))
- .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, getPhoneType(getJsonString(phone, "type")))
- .build());
- }
-
- /**
- * Add a phone to a list of database actions to be performed
- *
- * @param ops the list of database actions
- * @param phone the item to be inserted
- */
- private void insertPhoto(ArrayList ops,
- JSONObject photo) {
- byte[] bytes = getPhotoBytes(getJsonString(photo, "value"));
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes)
- .build());
- }
-
- /**
- * Gets the raw bytes from the supplied filename
- *
- * @param filename the file to read the bytes from
- * @return a byte array
- * @throws IOException
- */
- private byte[] getPhotoBytes(String filename) {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- try {
- int bytesRead = 0;
- long totalBytesRead = 0;
- byte[] data = new byte[8192];
- InputStream in = getPathFromUri(filename);
-
- while ((bytesRead = in.read(data, 0, data.length)) != -1 && totalBytesRead <= MAX_PHOTO_SIZE) {
- buffer.write(data, 0, bytesRead);
- totalBytesRead += bytesRead;
- }
-
- in.close();
- buffer.flush();
- } catch (FileNotFoundException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- } catch (IOException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return buffer.toByteArray();
- }
-
- /**
- * Get an input stream based on file path or uri content://, http://, file://
- *
- * @param path
- * @return an input stream
- * @throws IOException
- */
- private InputStream getPathFromUri(String path) throws IOException {
- if (path.startsWith("content:")) {
- Uri uri = Uri.parse(path);
- return mApp.getActivity().getContentResolver().openInputStream(uri);
- }
- if (path.startsWith("http:") || path.startsWith("https:") || path.startsWith("file:")) {
- URL url = new URL(path);
- return url.openStream();
- }
- else {
- return new FileInputStream(path);
- }
- }
-
- /**
- * Creates a new contact and stores it in the database
- *
- * @param contact the contact to be saved
- * @param account the account to be saved under
- */
- private String createNewContact(JSONObject contact, String accountType, String accountName) {
- // Create a list of attributes to add to the contact database
- ArrayList ops = new ArrayList();
-
- //Add contact type
- ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
- .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
- .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
- .build());
-
- // Add name
- try {
- JSONObject name = contact.optJSONObject("name");
- String displayName = contact.getString("displayName");
- if (displayName != null || name != null) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName)
- .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, getJsonString(name, "familyName"))
- .withValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, getJsonString(name, "middleName"))
- .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, getJsonString(name, "givenName"))
- .withValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX, getJsonString(name, "honorificPrefix"))
- .withValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, getJsonString(name, "honorificSuffix"))
- .build());
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get name object");
- }
-
- //Add phone numbers
- JSONArray phones = null;
- try {
- phones = contact.getJSONArray("phoneNumbers");
- if (phones != null) {
- for (int i = 0; i < phones.length(); i++) {
- JSONObject phone = (JSONObject) phones.get(i);
- insertPhone(ops, phone);
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get phone numbers");
- }
-
- // Add emails
- JSONArray emails = null;
- try {
- emails = contact.getJSONArray("emails");
- if (emails != null) {
- for (int i = 0; i < emails.length(); i++) {
- JSONObject email = (JSONObject) emails.get(i);
- insertEmail(ops, email);
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get emails");
- }
-
- // Add addresses
- JSONArray addresses = null;
- try {
- addresses = contact.getJSONArray("addresses");
- if (addresses != null) {
- for (int i = 0; i < addresses.length(); i++) {
- JSONObject address = (JSONObject) addresses.get(i);
- insertAddress(ops, address);
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get addresses");
- }
-
- // Add organizations
- JSONArray organizations = null;
- try {
- organizations = contact.getJSONArray("organizations");
- if (organizations != null) {
- for (int i = 0; i < organizations.length(); i++) {
- JSONObject org = (JSONObject) organizations.get(i);
- insertOrganization(ops, org);
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get organizations");
- }
-
- // Add IMs
- JSONArray ims = null;
- try {
- ims = contact.getJSONArray("ims");
- if (ims != null) {
- for (int i = 0; i < ims.length(); i++) {
- JSONObject im = (JSONObject) ims.get(i);
- insertIm(ops, im);
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get emails");
- }
-
- // Add note
- String note = getJsonString(contact, "note");
- if (note != null) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Note.NOTE, note)
- .build());
- }
-
- // Add nickname
- String nickname = getJsonString(contact, "nickname");
- if (nickname != null) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Nickname.NAME, nickname)
- .build());
- }
-
- // Add urls
- JSONArray websites = null;
- try {
- websites = contact.getJSONArray("urls");
- if (websites != null) {
- for (int i = 0; i < websites.length(); i++) {
- JSONObject website = (JSONObject) websites.get(i);
- insertWebsite(ops, website);
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get websites");
- }
-
- // Add birthday
- String birthday = getJsonString(contact, "birthday");
- if (birthday != null) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Event.TYPE, ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY)
- .withValue(ContactsContract.CommonDataKinds.Event.START_DATE, birthday)
- .build());
- }
-
- // Add photos
- JSONArray photos = null;
- try {
- photos = contact.getJSONArray("photos");
- if (photos != null) {
- for (int i = 0; i < photos.length(); i++) {
- JSONObject photo = (JSONObject) photos.get(i);
- insertPhoto(ops, photo);
- }
- }
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Could not get photos");
- }
-
- String newId = null;
- //Add contact
- try {
- ContentProviderResult[] cpResults = mApp.getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
- if (cpResults.length >= 0) {
- newId = cpResults[0].uri.getLastPathSegment();
- }
- } catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- } catch (OperationApplicationException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return newId;
- }
-
- @Override
- /**
- * This method will remove a Contact from the database based on ID.
- * @param id the unique ID of the contact to remove
- */
- public boolean remove(String id) {
- int result = 0;
- Cursor cursor = mApp.getActivity().getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
- null,
- ContactsContract.Contacts._ID + " = ?",
- new String[] { id }, null);
- if (cursor.getCount() == 1) {
- cursor.moveToFirst();
- String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
- Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
- result = mApp.getActivity().getContentResolver().delete(uri, null, null);
- } else {
- Log.d(LOG_TAG, "Could not find contact with ID");
- }
-
- return (result > 0) ? true : false;
- }
-
- /**************************************************************************
- *
- * All methods below this comment are used to convert from JavaScript
- * text types to Android integer types and vice versa.
- *
- *************************************************************************/
-
- /**
- * Converts a string from the W3C Contact API to it's Android int value.
- * @param string
- * @return Android int value
- */
- private int getPhoneType(String string) {
- int type = ContactsContract.CommonDataKinds.Phone.TYPE_OTHER;
- if (string != null) {
- if ("home".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_HOME;
- }
- else if ("mobile".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE;
- }
- else if ("work".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_WORK;
- }
- else if ("work fax".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK;
- }
- else if ("home fax".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_FAX_HOME;
- }
- else if ("fax".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK;
- }
- else if ("pager".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_PAGER;
- }
- else if ("other".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_OTHER;
- }
- else if ("car".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_CAR;
- }
- else if ("company main".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_COMPANY_MAIN;
- }
- else if ("isdn".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_ISDN;
- }
- else if ("main".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_MAIN;
- }
- else if ("other fax".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_OTHER_FAX;
- }
- else if ("radio".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_RADIO;
- }
- else if ("telex".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_TELEX;
- }
- else if ("work mobile".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_WORK_MOBILE;
- }
- else if ("work pager".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_WORK_PAGER;
- }
- else if ("assistant".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_ASSISTANT;
- }
- else if ("mms".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_MMS;
- }
- else if ("callback".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_CALLBACK;
- }
- else if ("tty ttd".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_TTY_TDD;
- }
- else if ("custom".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM;
- }
- }
- return type;
- }
-
- /**
- * getPhoneType converts an Android phone type into a string
- * @param type
- * @return phone type as string.
- */
- private String getPhoneType(int type) {
- String stringType;
- switch (type) {
- case ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM:
- stringType = "custom";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_HOME:
- stringType = "home fax";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK:
- stringType = "work fax";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_HOME:
- stringType = "home";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
- stringType = "mobile";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_PAGER:
- stringType = "pager";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_WORK:
- stringType = "work";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_CALLBACK:
- stringType = "callback";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_CAR:
- stringType = "car";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_COMPANY_MAIN:
- stringType = "company main";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_OTHER_FAX:
- stringType = "other fax";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_RADIO:
- stringType = "radio";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_TELEX:
- stringType = "telex";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_TTY_TDD:
- stringType = "tty tdd";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_WORK_MOBILE:
- stringType = "work mobile";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_WORK_PAGER:
- stringType = "work pager";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_ASSISTANT:
- stringType = "assistant";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_MMS:
- stringType = "mms";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_ISDN:
- stringType = "isdn";
- break;
- case ContactsContract.CommonDataKinds.Phone.TYPE_OTHER:
- default:
- stringType = "other";
- break;
- }
- return stringType;
- }
-
- /**
- * Converts a string from the W3C Contact API to it's Android int value.
- * @param string
- * @return Android int value
- */
- private int getContactType(String string) {
- int type = ContactsContract.CommonDataKinds.Email.TYPE_OTHER;
- if (string != null) {
- if ("home".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Email.TYPE_HOME;
- }
- else if ("work".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Email.TYPE_WORK;
- }
- else if ("other".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Email.TYPE_OTHER;
- }
- else if ("mobile".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Email.TYPE_MOBILE;
- }
- else if ("custom".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM;
- }
- }
- return type;
- }
-
- /**
- * getPhoneType converts an Android phone type into a string
- * @param type
- * @return phone type as string.
- */
- private String getContactType(int type) {
- String stringType;
- switch (type) {
- case ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM:
- stringType = "custom";
- break;
- case ContactsContract.CommonDataKinds.Email.TYPE_HOME:
- stringType = "home";
- break;
- case ContactsContract.CommonDataKinds.Email.TYPE_WORK:
- stringType = "work";
- break;
- case ContactsContract.CommonDataKinds.Email.TYPE_MOBILE:
- stringType = "mobile";
- break;
- case ContactsContract.CommonDataKinds.Email.TYPE_OTHER:
- default:
- stringType = "other";
- break;
- }
- return stringType;
- }
-
- /**
- * Converts a string from the W3C Contact API to it's Android int value.
- * @param string
- * @return Android int value
- */
- private int getOrgType(String string) {
- int type = ContactsContract.CommonDataKinds.Organization.TYPE_OTHER;
- if (string != null) {
- if ("work".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Organization.TYPE_WORK;
- }
- else if ("other".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Organization.TYPE_OTHER;
- }
- else if ("custom".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Organization.TYPE_CUSTOM;
- }
- }
- return type;
- }
-
- /**
- * getPhoneType converts an Android phone type into a string
- * @param type
- * @return phone type as string.
- */
- private String getOrgType(int type) {
- String stringType;
- switch (type) {
- case ContactsContract.CommonDataKinds.Organization.TYPE_CUSTOM:
- stringType = "custom";
- break;
- case ContactsContract.CommonDataKinds.Organization.TYPE_WORK:
- stringType = "work";
- break;
- case ContactsContract.CommonDataKinds.Organization.TYPE_OTHER:
- default:
- stringType = "other";
- break;
- }
- return stringType;
- }
-
- /**
- * Converts a string from the W3C Contact API to it's Android int value.
- * @param string
- * @return Android int value
- */
- private int getAddressType(String string) {
- int type = ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER;
- if (string != null) {
- if ("work".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK;
- }
- else if ("other".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER;
- }
- else if ("home".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME;
- }
- }
- return type;
- }
-
- /**
- * getPhoneType converts an Android phone type into a string
- * @param type
- * @return phone type as string.
- */
- private String getAddressType(int type) {
- String stringType;
- switch (type) {
- case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME:
- stringType = "home";
- break;
- case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK:
- stringType = "work";
- break;
- case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER:
- default:
- stringType = "other";
- break;
- }
- return stringType;
- }
-
- /**
- * Converts a string from the W3C Contact API to it's Android int value.
- * @param string
- * @return Android int value
- */
- private int getImType(String string) {
- int type = ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM;
- if (string != null) {
- if ("aim".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Im.PROTOCOL_AIM;
- }
- else if ("google talk".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Im.PROTOCOL_GOOGLE_TALK;
- }
- else if ("icq".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Im.PROTOCOL_ICQ;
- }
- else if ("jabber".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER;
- }
- else if ("msn".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Im.PROTOCOL_MSN;
- }
- else if ("netmeeting".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Im.PROTOCOL_NETMEETING;
- }
- else if ("qq".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Im.PROTOCOL_QQ;
- }
- else if ("skype".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Im.PROTOCOL_SKYPE;
- }
- else if ("yahoo".equals(string.toLowerCase())) {
- return ContactsContract.CommonDataKinds.Im.PROTOCOL_YAHOO;
- }
- }
- return type;
- }
-
- /**
- * getPhoneType converts an Android phone type into a string
- * @param type
- * @return phone type as string.
- */
- private String getImType(int type) {
- String stringType;
- switch (type) {
- case ContactsContract.CommonDataKinds.Im.PROTOCOL_AIM:
- stringType = "AIM";
- break;
- case ContactsContract.CommonDataKinds.Im.PROTOCOL_GOOGLE_TALK:
- stringType = "Google Talk";
- break;
- case ContactsContract.CommonDataKinds.Im.PROTOCOL_ICQ:
- stringType = "ICQ";
- break;
- case ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER:
- stringType = "Jabber";
- break;
- case ContactsContract.CommonDataKinds.Im.PROTOCOL_MSN:
- stringType = "MSN";
- break;
- case ContactsContract.CommonDataKinds.Im.PROTOCOL_NETMEETING:
- stringType = "NetMeeting";
- break;
- case ContactsContract.CommonDataKinds.Im.PROTOCOL_QQ:
- stringType = "QQ";
- break;
- case ContactsContract.CommonDataKinds.Im.PROTOCOL_SKYPE:
- stringType = "Skype";
- break;
- case ContactsContract.CommonDataKinds.Im.PROTOCOL_YAHOO:
- stringType = "Yahoo";
- break;
- default:
- stringType = "custom";
- break;
- }
- return stringType;
- }
-}
-
diff --git a/framework/src/org/apache/cordova/ContactManager.java b/framework/src/org/apache/cordova/ContactManager.java
deleted file mode 100755
index 8ea64a64..00000000
--- a/framework/src/org/apache/cordova/ContactManager.java
+++ /dev/null
@@ -1,122 +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 org.apache.cordova;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import android.util.Log;
-
-public class ContactManager extends CordovaPlugin {
-
- 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 JSONArray of arguments for the plugin.
- * @param callbackContext The callback context used when calling back into JavaScript.
- * @return True if the action was valid, false otherwise.
- */
- public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
- /**
- * 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 Cordova 1.0.
- */
- if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, ContactManager.NOT_SUPPORTED_ERROR));
- return true;
- }
-
- /**
- * 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.cordova);
- }
-
- if (action.equals("search")) {
- final JSONArray filter = args.getJSONArray(0);
- final JSONObject options = args.getJSONObject(1);
- this.cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- JSONArray res = contactAccessor.search(filter, options);
- callbackContext.success(res);
- }
- });
- }
- else if (action.equals("save")) {
- final JSONObject contact = args.getJSONObject(0);
- this.cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- JSONObject res = null;
- String id = contactAccessor.save(contact);
- if (id != null) {
- try {
- res = contactAccessor.getContactById(id);
- } catch (JSONException e) {
- Log.e(LOG_TAG, "JSON fail.", e);
- }
- }
- if (res != null) {
- callbackContext.success(res);
- } else {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR));
- }
- }
- });
- }
- else if (action.equals("remove")) {
- final String contactId = args.getString(0);
- this.cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- if (contactAccessor.remove(contactId)) {
- callbackContext.success();
- } else {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR));
- }
- }
- });
- }
- else {
- return false;
- }
- return true;
- }
-}
diff --git a/framework/src/org/apache/cordova/Echo.java b/framework/src/org/apache/cordova/Echo.java
deleted file mode 100644
index aaebe024..00000000
--- a/framework/src/org/apache/cordova/Echo.java
+++ /dev/null
@@ -1,48 +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 org.apache.cordova;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.json.JSONException;
-
-public class Echo extends CordovaPlugin {
-
- @Override
- public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
- if ("echo".equals(action)) {
- final String result = args.isNull(0) ? null : args.getString(0);
- callbackContext.success(result);
- return true;
- } else if ("echoAsync".equals(action)) {
- final String result = args.isNull(0) ? null : args.getString(0);
- cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- callbackContext.success(result);
- }
- });
- return true;
- } else if ("echoArrayBuffer".equals(action)) {
- final byte[] result = args.getArrayBuffer(0);
- callbackContext.success(result);
- return true;
- }
- return false;
- }
-}
diff --git a/framework/src/org/apache/cordova/FileProgressResult.java b/framework/src/org/apache/cordova/FileProgressResult.java
deleted file mode 100644
index d9811755..00000000
--- a/framework/src/org/apache/cordova/FileProgressResult.java
+++ /dev/null
@@ -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 org.apache.cordova;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Encapsulates in-progress status of uploading or downloading a file to a remote server.
- */
-public class FileProgressResult {
-
- private boolean lengthComputable = false; // declares whether total is known
- private long loaded = 0; // bytes sent so far
- private long total = 0; // bytes total, if known
-
- public boolean getLengthComputable() {
- return lengthComputable;
- }
-
- public void setLengthComputable(boolean computable) {
- this.lengthComputable = computable;
- }
-
- public long getLoaded() {
- return loaded;
- }
-
- public void setLoaded(long bytes) {
- this.loaded = bytes;
- }
-
- public long getTotal() {
- return total;
- }
-
- public void setTotal(long bytes) {
- this.total = bytes;
- }
-
- public JSONObject toJSONObject() throws JSONException {
- return new JSONObject(
- "{loaded:" + loaded +
- ",total:" + total +
- ",lengthComputable:" + (lengthComputable ? "true" : "false") + "}");
- }
-}
diff --git a/framework/src/org/apache/cordova/FileTransfer.java b/framework/src/org/apache/cordova/FileTransfer.java
deleted file mode 100644
index c87683f6..00000000
--- a/framework/src/org/apache/cordova/FileTransfer.java
+++ /dev/null
@@ -1,964 +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 org.apache.cordova;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLDecoder;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.Inflater;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.net.Uri;
-import android.os.Build;
-import android.util.Log;
-import android.webkit.CookieManager;
-
-import com.squareup.okhttp.OkHttpClient;
-
-public class FileTransfer extends CordovaPlugin {
-
- 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 BOUNDARY = "+++++";
-
- public static int FILE_NOT_FOUND_ERR = 1;
- public static int INVALID_URL_ERR = 2;
- public static int CONNECTION_ERR = 3;
- public static int ABORTED_ERR = 4;
-
- private static HashMap activeRequests = new HashMap();
- private static final int MAX_BUFFER_SIZE = 16 * 1024;
-
- private static OkHttpClient httpClient = new OkHttpClient();
-
- private static final class RequestContext {
- String source;
- String target;
- File targetFile;
- CallbackContext callbackContext;
- InputStream currentInputStream;
- OutputStream currentOutputStream;
- boolean aborted;
- RequestContext(String source, String target, CallbackContext callbackContext) {
- this.source = source;
- this.target = target;
- this.callbackContext = callbackContext;
- }
- void sendPluginResult(PluginResult pluginResult) {
- synchronized (this) {
- if (!aborted) {
- callbackContext.sendPluginResult(pluginResult);
- }
- }
- }
- }
-
- /**
- * Adds an interface method to an InputStream to return the number of bytes
- * read from the raw stream. This is used to track total progress against
- * the HTTP Content-Length header value from the server.
- */
- private static abstract class TrackingInputStream extends FilterInputStream {
- public TrackingInputStream(final InputStream in) {
- super(in);
- }
- public abstract long getTotalRawBytesRead();
- }
-
- private static class ExposedGZIPInputStream extends GZIPInputStream {
- public ExposedGZIPInputStream(final InputStream in) throws IOException {
- super(in);
- }
- public Inflater getInflater() {
- return inf;
- }
- }
-
- /**
- * Provides raw bytes-read tracking for a GZIP input stream. Reports the
- * total number of compressed bytes read from the input, rather than the
- * number of uncompressed bytes.
- */
- private static class TrackingGZIPInputStream extends TrackingInputStream {
- private ExposedGZIPInputStream gzin;
- public TrackingGZIPInputStream(final ExposedGZIPInputStream gzin) throws IOException {
- super(gzin);
- this.gzin = gzin;
- }
- public long getTotalRawBytesRead() {
- return gzin.getInflater().getBytesRead();
- }
- }
-
- /**
- * Provides simple total-bytes-read tracking for an existing InputStream
- */
- private static class TrackingHTTPInputStream extends TrackingInputStream {
- private long bytesRead = 0;
- public TrackingHTTPInputStream(InputStream stream) {
- super(stream);
- }
-
- private int updateBytesRead(int newBytesRead) {
- if (newBytesRead != -1) {
- bytesRead += newBytesRead;
- }
- return newBytesRead;
- }
-
- @Override
- public int read() throws IOException {
- return updateBytesRead(super.read());
- }
-
- @Override
- public int read(byte[] buffer) throws IOException {
- return updateBytesRead(super.read(buffer));
- }
-
- @Override
- public int read(byte[] bytes, int offset, int count) throws IOException {
- return updateBytesRead(super.read(bytes, offset, count));
- }
-
- public long getTotalRawBytesRead() {
- return bytesRead;
- }
- }
-
- /**
- * Works around a bug on Android 2.3.
- * http://code.google.com/p/android/issues/detail?id=14562
- */
- private static final class DoneHandlerInputStream extends TrackingHTTPInputStream {
- private boolean done;
-
- public DoneHandlerInputStream(InputStream stream) {
- super(stream);
- }
-
- @Override
- public int read() throws IOException {
- int result = done ? -1 : super.read();
- done = (result == -1);
- return result;
- }
-
- @Override
- public int read(byte[] buffer) throws IOException {
- int result = done ? -1 : super.read(buffer);
- done = (result == -1);
- return result;
- }
-
- @Override
- public int read(byte[] bytes, int offset, int count) throws IOException {
- int result = done ? -1 : super.read(bytes, offset, count);
- done = (result == -1);
- return result;
- }
- }
-
- @Override
- public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
- if (action.equals("upload") || action.equals("download")) {
- String source = args.getString(0);
- String target = args.getString(1);
-
- if (action.equals("upload")) {
- try {
- source = URLDecoder.decode(source, "UTF-8");
- upload(source, target, args, callbackContext);
- } catch (UnsupportedEncodingException e) {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.MALFORMED_URL_EXCEPTION, "UTF-8 error."));
- }
- } else {
- download(source, target, args, callbackContext);
- }
- return true;
- } else if (action.equals("abort")) {
- String objectId = args.getString(0);
- abort(objectId);
- callbackContext.success();
- return true;
- }
- return false;
- }
-
- private static void addHeadersToRequest(URLConnection connection, JSONObject headers) {
- try {
- for (Iterator> iter = headers.keys(); iter.hasNext(); ) {
- String headerKey = iter.next().toString();
- JSONArray headerValues = headers.optJSONArray(headerKey);
- if (headerValues == null) {
- headerValues = new JSONArray();
- headerValues.put(headers.getString(headerKey));
- }
- connection.setRequestProperty(headerKey, headerValues.getString(0));
- for (int i = 1; i < headerValues.length(); ++i) {
- connection.addRequestProperty(headerKey, headerValues.getString(i));
- }
- }
- } catch (JSONException e1) {
- // No headers to be manipulated!
- }
- }
-
- /**
- * Uploads the specified file to the server URL provided using an HTTP multipart request.
- * @param source Full path of the file on the file system
- * @param target URL of the server to receive the file
- * @param args JSON Array of args
- * @param callbackContext callback id for optional progress reports
- *
- * args[2] fileKey Name of file request parameter
- * args[3] fileName File name to be used on server
- * args[4] mimeType Describes file content type
- * args[5] params key:value pairs of user-defined parameters
- * @return FileUploadResult containing result of upload request
- */
- private void upload(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
- Log.d(LOG_TAG, "upload " + source + " to " + target);
-
- // Setup the options
- final String fileKey = getArgument(args, 2, "file");
- final String fileName = getArgument(args, 3, "image.jpg");
- final String mimeType = getArgument(args, 4, "image/jpeg");
- final JSONObject params = args.optJSONObject(5) == null ? new JSONObject() : args.optJSONObject(5);
- final boolean trustEveryone = args.optBoolean(6);
- // Always use chunked mode unless set to false as per API
- final boolean chunkedMode = args.optBoolean(7) || args.isNull(7);
- // Look for headers on the params map for backwards compatibility with older Cordova versions.
- final JSONObject headers = args.optJSONObject(8) == null ? params.optJSONObject("headers") : args.optJSONObject(8);
- final String objectId = args.getString(9);
- final String httpMethod = getArgument(args, 10, "POST");
-
- Log.d(LOG_TAG, "fileKey: " + fileKey);
- Log.d(LOG_TAG, "fileName: " + fileName);
- Log.d(LOG_TAG, "mimeType: " + mimeType);
- Log.d(LOG_TAG, "params: " + params);
- Log.d(LOG_TAG, "trustEveryone: " + trustEveryone);
- Log.d(LOG_TAG, "chunkedMode: " + chunkedMode);
- Log.d(LOG_TAG, "headers: " + headers);
- Log.d(LOG_TAG, "objectId: " + objectId);
- Log.d(LOG_TAG, "httpMethod: " + httpMethod);
-
- final URL url;
- try {
- url = new URL(target);
- } catch (MalformedURLException e) {
- JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
- Log.e(LOG_TAG, error.toString(), e);
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- return;
- }
- final boolean useHttps = url.getProtocol().equals("https");
-
- final RequestContext context = new RequestContext(source, target, callbackContext);
- synchronized (activeRequests) {
- activeRequests.put(objectId, context);
- }
-
- cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- if (context.aborted) {
- return;
- }
- HttpURLConnection conn = null;
- HostnameVerifier oldHostnameVerifier = null;
- SSLSocketFactory oldSocketFactory = null;
- int totalBytes = 0;
- int fixedLength = -1;
- try {
- // Create return object
- FileUploadResult result = new FileUploadResult();
- FileProgressResult progress = new FileProgressResult();
-
- //------------------ CLIENT REQUEST
- // Open a HTTP connection to the URL based on protocol
- if (useHttps) {
- // Using standard HTTPS connection. Will not allow self signed certificate
- if (!trustEveryone) {
- conn = (HttpsURLConnection) httpClient.open(url);
- }
- // 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
- HttpsURLConnection https = (HttpsURLConnection) httpClient.open(url);
- oldSocketFactory = trustAllHosts(https);
- // Save the current hostnameVerifier
- oldHostnameVerifier = https.getHostnameVerifier();
- // Setup the connection not to verify hostnames
- https.setHostnameVerifier(DO_NOT_VERIFY);
- conn = https;
- }
- }
- // Return a standard HTTP connection
- else {
- conn = httpClient.open(url);
- }
-
- // 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(httpMethod);
- conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
-
- // Set the cookies on the response
- String cookie = CookieManager.getInstance().getCookie(target);
- if (cookie != null) {
- conn.setRequestProperty("Cookie", cookie);
- }
-
- // Handle the other headers
- if (headers != null) {
- addHeadersToRequest(conn, headers);
- }
-
- /*
- * Store the non-file portions of the multipart data as a string, so that we can add it
- * to the contentSize, since it is part of the body of the HTTP request.
- */
- StringBuilder beforeData = new StringBuilder();
- try {
- for (Iterator> iter = params.keys(); iter.hasNext();) {
- Object key = iter.next();
- if(!String.valueOf(key).equals("headers"))
- {
- beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
- beforeData.append("Content-Disposition: form-data; name=\"").append(key.toString()).append('"');
- beforeData.append(LINE_END).append(LINE_END);
- beforeData.append(params.getString(key.toString()));
- beforeData.append(LINE_END);
- }
- }
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
-
- beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
- beforeData.append("Content-Disposition: form-data; name=\"").append(fileKey).append("\";");
- beforeData.append(" filename=\"").append(fileName).append('"').append(LINE_END);
- beforeData.append("Content-Type: ").append(mimeType).append(LINE_END).append(LINE_END);
- byte[] beforeDataBytes = beforeData.toString().getBytes("UTF-8");
- byte[] tailParamsBytes = (LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END).getBytes("UTF-8");
-
-
- // Get a input stream of the file on the phone
- InputStream sourceInputStream = getPathFromUri(source);
-
- int stringLength = beforeDataBytes.length + tailParamsBytes.length;
- if (sourceInputStream instanceof FileInputStream) {
- fixedLength = (int) ((FileInputStream)sourceInputStream).getChannel().size() + stringLength;
- progress.setLengthComputable(true);
- progress.setTotal(fixedLength);
- }
- Log.d(LOG_TAG, "Content Length: " + fixedLength);
- // setFixedLengthStreamingMode causes and OutOfMemoryException on pre-Froyo devices.
- // http://code.google.com/p/android/issues/detail?id=3164
- // It also causes OOM if HTTPS is used, even on newer devices.
- boolean useChunkedMode = chunkedMode && (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO || useHttps);
- useChunkedMode = useChunkedMode || (fixedLength == -1);
-
- if (useChunkedMode) {
- conn.setChunkedStreamingMode(MAX_BUFFER_SIZE);
- // Although setChunkedStreamingMode sets this header, setting it explicitly here works
- // around an OutOfMemoryException when using https.
- conn.setRequestProperty("Transfer-Encoding", "chunked");
- } else {
- conn.setFixedLengthStreamingMode(fixedLength);
- }
-
- conn.connect();
-
- OutputStream sendStream = null;
- try {
- sendStream = conn.getOutputStream();
- synchronized (context) {
- if (context.aborted) {
- return;
- }
- context.currentOutputStream = sendStream;
- }
- //We don't want to change encoding, we just want this to write for all Unicode.
- sendStream.write(beforeDataBytes);
- totalBytes += beforeDataBytes.length;
-
- // create a buffer of maximum size
- int bytesAvailable = sourceInputStream.available();
- int bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
- byte[] buffer = new byte[bufferSize];
-
- // read file and write it into form...
- int bytesRead = sourceInputStream.read(buffer, 0, bufferSize);
-
- long prevBytesRead = 0;
- while (bytesRead > 0) {
- result.setBytesSent(totalBytes);
- sendStream.write(buffer, 0, bytesRead);
- totalBytes += bytesRead;
- if (totalBytes > prevBytesRead + 102400) {
- prevBytesRead = totalBytes;
- Log.d(LOG_TAG, "Uploaded " + totalBytes + " of " + fixedLength + " bytes");
- }
- bytesAvailable = sourceInputStream.available();
- bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
- bytesRead = sourceInputStream.read(buffer, 0, bufferSize);
-
- // Send a progress event.
- progress.setLoaded(totalBytes);
- PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
- progressResult.setKeepCallback(true);
- context.sendPluginResult(progressResult);
- }
-
- // send multipart form data necessary after file data...
- sendStream.write(tailParamsBytes);
- totalBytes += tailParamsBytes.length;
- sendStream.flush();
- } finally {
- safeClose(sourceInputStream);
- safeClose(sendStream);
- }
- context.currentOutputStream = null;
- Log.d(LOG_TAG, "Sent " + totalBytes + " of " + fixedLength);
-
- //------------------ read the SERVER RESPONSE
- String responseString;
- int responseCode = conn.getResponseCode();
- Log.d(LOG_TAG, "response code: " + responseCode);
- Log.d(LOG_TAG, "response headers: " + conn.getHeaderFields());
- TrackingInputStream inStream = null;
- try {
- inStream = getInputStream(conn);
- synchronized (context) {
- if (context.aborted) {
- return;
- }
- context.currentInputStream = inStream;
- }
-
- ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(1024, conn.getContentLength()));
- byte[] buffer = new byte[1024];
- int bytesRead = 0;
- // write bytes to file
- while ((bytesRead = inStream.read(buffer)) > 0) {
- out.write(buffer, 0, bytesRead);
- }
- responseString = out.toString("UTF-8");
- } finally {
- context.currentInputStream = null;
- safeClose(inStream);
- }
-
- Log.d(LOG_TAG, "got response from server");
- Log.d(LOG_TAG, responseString.substring(0, Math.min(256, responseString.length())));
-
- // send request and retrieve response
- result.setResponseCode(responseCode);
- result.setResponse(responseString);
-
- context.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));
- } catch (FileNotFoundException e) {
- JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, conn);
- Log.e(LOG_TAG, error.toString(), e);
- context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- } catch (IOException e) {
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
- Log.e(LOG_TAG, error.toString(), e);
- Log.e(LOG_TAG, "Failed after uploading " + totalBytes + " of " + fixedLength + " bytes.");
- context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- context.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
- } catch (Throwable t) {
- // Shouldn't happen, but will
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
- Log.e(LOG_TAG, error.toString(), t);
- context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- } finally {
- synchronized (activeRequests) {
- activeRequests.remove(objectId);
- }
-
- if (conn != null) {
- // Revert back to the proper verifier and socket factories
- // Revert back to the proper verifier and socket factories
- if (trustEveryone && useHttps) {
- HttpsURLConnection https = (HttpsURLConnection) conn;
- https.setHostnameVerifier(oldHostnameVerifier);
- https.setSSLSocketFactory(oldSocketFactory);
- }
- }
- }
- }
- });
- }
-
- private static void safeClose(Closeable stream) {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- }
- }
- }
-
- private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
- return new DoneHandlerInputStream(conn.getInputStream());
- }
- String encoding = conn.getContentEncoding();
- if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
- return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
- }
- return new TrackingHTTPInputStream(conn.getInputStream());
- }
-
- // always verify the host - don't check for certificate
- private static final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
- public boolean verify(String hostname, SSLSession session) {
- return true;
- }
- };
- // Create a trust manager that does not validate certificate chains
- private static final 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 {
- }
- } };
-
- /**
- * 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 static SSLSocketFactory trustAllHosts(HttpsURLConnection connection) {
- // Install the all-trusting trust manager
- SSLSocketFactory oldFactory = connection.getSSLSocketFactory();
- try {
- // Install our all trusting manager
- SSLContext sc = SSLContext.getInstance("TLS");
- sc.init(null, trustAllCerts, new java.security.SecureRandom());
- SSLSocketFactory newFactory = sc.getSocketFactory();
- connection.setSSLSocketFactory(newFactory);
- } catch (Exception e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return oldFactory;
- }
-
- private static JSONObject createFileTransferError(int errorCode, String source, String target, URLConnection connection) {
-
- int httpStatus = 0;
- StringBuilder bodyBuilder = new StringBuilder();
- String body = null;
- if (connection != null) {
- try {
- if (connection instanceof HttpURLConnection) {
- httpStatus = ((HttpURLConnection)connection).getResponseCode();
- InputStream err = ((HttpURLConnection) connection).getErrorStream();
- if(err != null)
- {
- BufferedReader reader = new BufferedReader(new InputStreamReader(err, "UTF-8"));
- String line = reader.readLine();
- while(line != null)
- {
- bodyBuilder.append(line);
- line = reader.readLine();
- if(line != null)
- bodyBuilder.append('\n');
- }
- body = bodyBuilder.toString();
- }
- }
- } catch (IOException e) {
- Log.w(LOG_TAG, "Error getting HTTP status code from connection.", e);
- }
- }
-
- return createFileTransferError(errorCode, source, target, body, httpStatus);
- }
-
- /**
- * Create an error object based on the passed in errorCode
- * @param errorCode the error
- * @return JSONObject containing the error
- */
- private static JSONObject createFileTransferError(int errorCode, String source, String target, String body, Integer httpStatus) {
- JSONObject error = null;
- try {
- error = new JSONObject();
- error.put("code", errorCode);
- error.put("source", source);
- error.put("target", target);
- if(body != null)
- {
- error.put("body", body);
- }
- if (httpStatus != null) {
- error.put("http_status", httpStatus);
- }
- } 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 static 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;
- }
-
- /**
- * 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
- */
- private void download(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
- Log.d(LOG_TAG, "download " + source + " to " + target);
-
- final boolean trustEveryone = args.optBoolean(2);
- final String objectId = args.getString(3);
- final JSONObject headers = args.optJSONObject(4);
-
- final URL url;
- try {
- url = new URL(source);
- } catch (MalformedURLException e) {
- JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
- Log.e(LOG_TAG, error.toString(), e);
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- return;
- }
- final boolean useHttps = url.getProtocol().equals("https");
-
- if (!Config.isUrlWhiteListed(source)) {
- Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, null, 401);
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- return;
- }
-
-
- final RequestContext context = new RequestContext(source, target, callbackContext);
- synchronized (activeRequests) {
- activeRequests.put(objectId, context);
- }
-
- cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- if (context.aborted) {
- return;
- }
- URLConnection connection = null;
- HostnameVerifier oldHostnameVerifier = null;
- SSLSocketFactory oldSocketFactory = null;
- File file = null;
- PluginResult result = null;
-
- try {
- file = getFileFromPath(target);
- context.targetFile = file;
- // create needed directories
- file.getParentFile().mkdirs();
-
- // connect to server
- // Open a HTTP connection to the URL based on protocol
- if (useHttps) {
- // Using standard HTTPS connection. Will not allow self signed certificate
- if (!trustEveryone) {
- connection = (HttpsURLConnection) httpClient.open(url);
- }
- // 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
- HttpsURLConnection https = (HttpsURLConnection) httpClient.open(url);
- oldSocketFactory = trustAllHosts(https);
- // Save the current hostnameVerifier
- oldHostnameVerifier = https.getHostnameVerifier();
- // Setup the connection not to verify hostnames
- https.setHostnameVerifier(DO_NOT_VERIFY);
- connection = https;
- }
- }
- // Return a standard HTTP connection
- else {
- connection = httpClient.open(url);
-
- }
-
- if (connection instanceof HttpURLConnection) {
- ((HttpURLConnection)connection).setRequestMethod("GET");
- }
-
- //Add cookie support
- String cookie = CookieManager.getInstance().getCookie(source);
- if(cookie != null)
- {
- connection.setRequestProperty("cookie", cookie);
- }
-
- // This must be explicitly set for gzip progress tracking to work.
- connection.setRequestProperty("Accept-Encoding", "gzip");
-
- // Handle the other headers
- if (headers != null) {
- addHeadersToRequest(connection, headers);
- }
-
- connection.connect();
-
- Log.d(LOG_TAG, "Download file:" + url);
-
- FileProgressResult progress = new FileProgressResult();
- if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
- // Only trust content-length header if we understand
- // the encoding -- identity or gzip
- progress.setLengthComputable(true);
- progress.setTotal(connection.getContentLength());
- }
-
- FileOutputStream outputStream = null;
- TrackingInputStream inputStream = null;
-
- try {
- inputStream = getInputStream(connection);
- outputStream = new FileOutputStream(file);
- synchronized (context) {
- if (context.aborted) {
- return;
- }
- context.currentInputStream = inputStream;
- }
-
- // write bytes to file
- byte[] buffer = new byte[MAX_BUFFER_SIZE];
- int bytesRead = 0;
- while ((bytesRead = inputStream.read(buffer)) > 0) {
- outputStream.write(buffer, 0, bytesRead);
- // Send a progress event.
- progress.setLoaded(inputStream.getTotalRawBytesRead());
- PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
- progressResult.setKeepCallback(true);
- context.sendPluginResult(progressResult);
- }
- } finally {
- context.currentInputStream = null;
- safeClose(inputStream);
- safeClose(outputStream);
- }
-
- Log.d(LOG_TAG, "Saved file: " + target);
-
- // create FileEntry object
- JSONObject fileEntry = FileUtils.getEntry(file);
-
- result = new PluginResult(PluginResult.Status.OK, fileEntry);
- } catch (FileNotFoundException e) {
- JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, connection);
- Log.e(LOG_TAG, error.toString(), e);
- result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
- } catch (IOException e) {
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
- Log.e(LOG_TAG, error.toString(), e);
- result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- result = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
- } catch (Throwable e) {
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
- Log.e(LOG_TAG, error.toString(), e);
- result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
- } finally {
- synchronized (activeRequests) {
- activeRequests.remove(objectId);
- }
-
- if (connection != null) {
- // Revert back to the proper verifier and socket factories
- if (trustEveryone && useHttps) {
- HttpsURLConnection https = (HttpsURLConnection) connection;
- https.setHostnameVerifier(oldHostnameVerifier);
- https.setSSLSocketFactory(oldSocketFactory);
- }
- }
-
- if (result == null) {
- result = new PluginResult(PluginResult.Status.ERROR, createFileTransferError(CONNECTION_ERR, source, target, connection));
- }
- // Remove incomplete download.
- if (result.getStatus() != PluginResult.Status.OK.ordinal() && file != null) {
- file.delete();
- }
- context.sendPluginResult(result);
- }
- }
- });
- }
-
- /**
- * Get an input stream based on file path or content:// uri
- *
- * @param path foo
- * @return an input stream
- * @throws FileNotFoundException
- */
- private InputStream getPathFromUri(String path) throws FileNotFoundException {
- if (path.startsWith("content:")) {
- Uri uri = Uri.parse(path);
- return cordova.getActivity().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);
- }
- }
-
- /**
- * Get a File object from the passed in path
- *
- * @param path file path
- * @return file object
- */
- private File getFileFromPath(String path) throws FileNotFoundException {
- File file;
- String prefix = "file://";
-
- if (path.startsWith(prefix)) {
- file = new File(path.substring(prefix.length()));
- } else {
- file = new File(path);
- }
-
- if (file.getParent() == null) {
- throw new FileNotFoundException();
- }
-
- return file;
- }
-
- /**
- * Abort an ongoing upload or download.
- */
- private void abort(String objectId) {
- final RequestContext context;
- synchronized (activeRequests) {
- context = activeRequests.remove(objectId);
- }
- if (context != null) {
- File file = context.targetFile;
- if (file != null) {
- file.delete();
- }
- // Trigger the abort callback immediately to minimize latency between it and abort() being called.
- JSONObject error = createFileTransferError(ABORTED_ERR, context.source, context.target, null, -1);
- synchronized (context) {
- context.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, error));
- context.aborted = true;
- }
- // Closing the streams can block, so execute on a background thread.
- cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- synchronized (context) {
- safeClose(context.currentInputStream);
- safeClose(context.currentOutputStream);
- }
- }
- });
- }
- }
-}
diff --git a/framework/src/org/apache/cordova/FileUploadResult.java b/framework/src/org/apache/cordova/FileUploadResult.java
deleted file mode 100644
index b556869e..00000000
--- a/framework/src/org/apache/cordova/FileUploadResult.java
+++ /dev/null
@@ -1,73 +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 org.apache.cordova;
-
-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
- private String objectId = null; // FileTransfer object id
-
- 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 String getObjectId() {
- return objectId;
- }
-
- public void setObjectId(String objectId) {
- this.objectId = objectId;
- }
-
- public JSONObject toJSONObject() throws JSONException {
- return new JSONObject(
- "{bytesSent:" + bytesSent +
- ",responseCode:" + responseCode +
- ",response:" + JSONObject.quote(response) +
- ",objectId:" + JSONObject.quote(objectId) + "}");
- }
-}
diff --git a/framework/src/org/apache/cordova/FileUtils.java b/framework/src/org/apache/cordova/FileUtils.java
deleted file mode 100755
index e62fc4a1..00000000
--- a/framework/src/org/apache/cordova/FileUtils.java
+++ /dev/null
@@ -1,1024 +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 org.apache.cordova;
-
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.util.Log;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.DataResource;
-import org.apache.cordova.api.PluginResult;
-import org.apache.cordova.file.EncodingException;
-import org.apache.cordova.file.FileExistsException;
-import org.apache.cordova.file.InvalidModificationException;
-import org.apache.cordova.file.NoModificationAllowedException;
-import org.apache.cordova.file.TypeMismatchException;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.ByteArrayInputStream;
-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.io.RandomAccessFile;
-import java.net.MalformedURLException;
-import java.nio.channels.FileChannel;
-
-/**
- * This class provides SD card file and directory services to JavaScript.
- * Only files on the SD card can be accessed.
- */
-public class FileUtils extends CordovaPlugin {
- private static final String LOG_TAG = "FileUtils";
-
- public static int NOT_FOUND_ERR = 1;
- public static int SECURITY_ERR = 2;
- public static int ABORT_ERR = 3;
-
- public static int NOT_READABLE_ERR = 4;
- public static int ENCODING_ERR = 5;
- public static int NO_MODIFICATION_ALLOWED_ERR = 6;
- public static int INVALID_STATE_ERR = 7;
- public static int SYNTAX_ERR = 8;
- public static int INVALID_MODIFICATION_ERR = 9;
- public static int QUOTA_EXCEEDED_ERR = 10;
- public static int TYPE_MISMATCH_ERR = 11;
- public static int PATH_EXISTS_ERR = 12;
-
- public static int TEMPORARY = 0;
- public static int PERSISTENT = 1;
- public static int RESOURCE = 2;
- public static int APPLICATION = 3;
-
- /**
- * Constructor.
- */
- public FileUtils() {
- }
-
- /**
- * Executes the request and returns whether the action was valid.
- *
- * @param action The action to execute.
- * @param args JSONArray of arguments for the plugin.
- * @param callbackContext The callback context used when calling back into JavaScript.
- * @return True if the action was valid, false otherwise.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- try {
- if (action.equals("testSaveLocationExists")) {
- boolean b = DirectoryManager.testSaveLocationExists();
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
- }
- else if (action.equals("getFreeDiskSpace")) {
- long l = DirectoryManager.getFreeDiskSpace(false);
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, l));
- }
- else if (action.equals("testFileExists")) {
- boolean b = DirectoryManager.testFileExists(args.getString(0));
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
- }
- else if (action.equals("testDirectoryExists")) {
- boolean b = DirectoryManager.testFileExists(args.getString(0));
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
- }
- else if (action.equals("readAsText")) {
- String encoding = args.getString(1);
- int start = args.getInt(2);
- int end = args.getInt(3);
-
- this.readFileAs(args.getString(0), start, end, callbackContext, encoding, PluginResult.MESSAGE_TYPE_STRING);
- }
- else if (action.equals("readAsDataURL")) {
- int start = args.getInt(1);
- int end = args.getInt(2);
-
- this.readFileAs(args.getString(0), start, end, callbackContext, null, -1);
- }
- else if (action.equals("readAsArrayBuffer")) {
- int start = args.getInt(1);
- int end = args.getInt(2);
-
- this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_ARRAYBUFFER);
- }
- else if (action.equals("readAsBinaryString")) {
- int start = args.getInt(1);
- int end = args.getInt(2);
-
- this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_BINARYSTRING);
- }
- else if (action.equals("write")) {
- long fileSize = this.write(args.getString(0), args.getString(1), args.getInt(2));
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize));
- }
- else if (action.equals("truncate")) {
- long fileSize = this.truncateFile(args.getString(0), args.getLong(1));
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize));
- }
- else if (action.equals("requestFileSystem")) {
- long size = args.optLong(1);
- if (size != 0 && size > (DirectoryManager.getFreeDiskSpace(true) * 1024)) {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, FileUtils.QUOTA_EXCEEDED_ERR));
- } else {
- JSONObject obj = requestFileSystem(args.getInt(0));
- callbackContext.success(obj);
- }
- }
- else if (action.equals("resolveLocalFileSystemURI")) {
- JSONObject obj = resolveLocalFileSystemURI(args.getString(0));
- callbackContext.success(obj);
- }
- else if (action.equals("getMetadata")) {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, getMetadata(args.getString(0))));
- }
- else if (action.equals("getFileMetadata")) {
- JSONObject obj = getFileMetadata(args.getString(0));
- callbackContext.success(obj);
- }
- else if (action.equals("getParent")) {
- JSONObject obj = getParent(args.getString(0));
- callbackContext.success(obj);
- }
- else if (action.equals("getDirectory")) {
- JSONObject obj = getFile(args.getString(0), args.getString(1), args.optJSONObject(2), true);
- callbackContext.success(obj);
- }
- else if (action.equals("getFile")) {
- JSONObject obj = getFile(args.getString(0), args.getString(1), args.optJSONObject(2), false);
- callbackContext.success(obj);
- }
- else if (action.equals("remove")) {
- boolean success;
-
- success = remove(args.getString(0));
-
- if (success) {
- notifyDelete(args.getString(0));
- callbackContext.success();
- } else {
- callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
- }
- }
- else if (action.equals("removeRecursively")) {
- boolean success = removeRecursively(args.getString(0));
- if (success) {
- callbackContext.success();
- } else {
- callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
- }
- }
- else if (action.equals("moveTo")) {
- JSONObject entry = transferTo(args.getString(0), args.getString(1), args.getString(2), true);
- callbackContext.success(entry);
- }
- else if (action.equals("copyTo")) {
- JSONObject entry = transferTo(args.getString(0), args.getString(1), args.getString(2), false);
- callbackContext.success(entry);
- }
- else if (action.equals("readEntries")) {
- JSONArray entries = readEntries(args.getString(0));
- callbackContext.success(entries);
- }
- else {
- return false;
- }
- } catch (FileNotFoundException e) {
- callbackContext.error(FileUtils.NOT_FOUND_ERR);
- } catch (FileExistsException e) {
- callbackContext.error(FileUtils.PATH_EXISTS_ERR);
- } catch (NoModificationAllowedException e) {
- callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
- } catch (InvalidModificationException e) {
- callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR);
- } catch (MalformedURLException e) {
- callbackContext.error(FileUtils.ENCODING_ERR);
- } catch (IOException e) {
- callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR);
- } catch (EncodingException e) {
- callbackContext.error(FileUtils.ENCODING_ERR);
- } catch (TypeMismatchException e) {
- callbackContext.error(FileUtils.TYPE_MISMATCH_ERR);
- }
- return true;
- }
-
- /**
- * Need to check to see if we need to clean up the content store
- *
- * @param filePath the path to check
- */
- private void notifyDelete(String filePath) {
- String newFilePath = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.notifyDelete").getRealFile().getPath();
- try {
- this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
- MediaStore.Images.Media.DATA + " = ?",
- new String[] { newFilePath });
- } catch (UnsupportedOperationException t) {
- // Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator.
- // The ContentResolver applies only when the file was registered in the
- // first case, which is generally only the case with images.
- }
- }
-
- /**
- * Allows the user to look up the Entry for a file or directory referred to by a local URI.
- *
- * @param url of the file/directory to look up
- * @return a JSONObject representing a Entry from the filesystem
- * @throws MalformedURLException if the url is not valid
- * @throws FileNotFoundException if the file does not exist
- * @throws IOException if the user can't read the file
- * @throws JSONException
- */
- private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException {
- File fp = DataResource.initiateNewDataRequestForUri(url, webView.pluginManager, cordova, "FileUtils.resolveLocalFileSystemURI").getRealFile();
-
- if (fp == null || !fp.exists()) {
- throw new FileNotFoundException();
- }
- if (!fp.canRead()) {
- throw new IOException();
- }
- return getEntry(fp);
- }
-
- /**
- * Read the list of files from this directory.
- *
- * @param fileName the directory to read from
- * @return a JSONArray containing JSONObjects that represent Entry objects.
- * @throws FileNotFoundException if the directory is not found.
- * @throws JSONException
- */
- private JSONArray readEntries(String fileName) throws FileNotFoundException, JSONException {
- File fp = DataResource.initiateNewDataRequestForUri(fileName, webView.pluginManager, cordova, "FileUtils.readEntries").getRealFile();
-
- if (fp == null || !fp.exists()) {
- // The directory we are listing doesn't exist so we should fail.
- throw new FileNotFoundException();
- }
-
- JSONArray entries = new JSONArray();
-
- if (fp.isDirectory()) {
- File[] files = fp.listFiles();
- for (int i = 0; i < files.length; i++) {
- if (files[i].canRead()) {
- entries.put(getEntry(files[i]));
- }
- }
- }
-
- return entries;
- }
-
- /**
- * A setup method that handles the move/copy of files/directories
- *
- * @param fileName to be copied/moved
- * @param newParent is the location where the file will be copied/moved to
- * @param newName for the file directory to be called, if null use existing file name
- * @param move if false do a copy, if true do a move
- * @return a Entry object
- * @throws NoModificationAllowedException
- * @throws IOException
- * @throws InvalidModificationException
- * @throws EncodingException
- * @throws JSONException
- * @throws FileExistsException
- */
- private JSONObject transferTo(String fileName, String newParent, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
- DataResource dataResourceFrom = DataResource.initiateNewDataRequestForUri(fileName, webView.pluginManager, cordova, "FileUtils.transferTo");
- String newFileName = dataResourceFrom.getRealFile().getPath();
- DataResource dataResourceTo = DataResource.initiateNewDataRequestForUri(newParent, webView.pluginManager, cordova, "FileUtils.transferTo");
- newParent = dataResourceTo.getRealFile().getPath();
-
- // Check for invalid file name
- if (newName != null && newName.contains(":")) {
- throw new EncodingException("Bad file name");
- }
-
- File source = new File(newFileName);
-
- if (!source.exists()) {
- // The file/directory we are copying doesn't exist so we should fail.
- throw new FileNotFoundException("The source does not exist");
- }
-
- File destinationDir = new File(newParent);
- if (!destinationDir.exists()) {
- // The destination does not exist so we should fail.
- throw new FileNotFoundException("The source does not exist");
- }
-
- // Figure out where we should be copying to
- File destination = createDestination(newName, source, destinationDir);
-
- //Log.d(LOG_TAG, "Source: " + source.getAbsolutePath());
- //Log.d(LOG_TAG, "Destin: " + destination.getAbsolutePath());
-
- // Check to see if source and destination are the same file
- if (source.getAbsolutePath().equals(destination.getAbsolutePath())) {
- throw new InvalidModificationException("Can't copy a file onto itself");
- }
-
- if (source.isDirectory()) {
- if (move) {
- return moveDirectory(source, destination);
- } else {
- return copyDirectory(source, destination);
- }
- } else {
- if (move) {
- JSONObject newFileEntry = moveFile(source, destination);
-
- // If we've moved a file given its content URI, we need to clean up.
- if (fileName.startsWith("content://")) {
- notifyDelete(fileName);
- }
-
- return newFileEntry;
- } else {
- return copyFile(source, destination);
- }
- }
- }
-
- /**
- * Creates the destination File object based on name passed in
- *
- * @param newName for the file directory to be called, if null use existing file name
- * @param fp represents the source file
- * @param destination represents the destination file
- * @return a File object that represents the destination
- */
- private File createDestination(String newName, File fp, File destination) {
- File destFile = null;
-
- // I know this looks weird but it is to work around a JSON bug.
- if ("null".equals(newName) || "".equals(newName)) {
- newName = null;
- }
-
- if (newName != null) {
- destFile = new File(destination.getAbsolutePath() + File.separator + newName);
- } else {
- destFile = new File(destination.getAbsolutePath() + File.separator + fp.getName());
- }
- return destFile;
- }
-
- /**
- * Copy a file
- *
- * @param srcFile file to be copied
- * @param destFile destination to be copied to
- * @return a FileEntry object
- * @throws IOException
- * @throws InvalidModificationException
- * @throws JSONException
- */
- private JSONObject copyFile(File srcFile, File destFile) throws IOException, InvalidModificationException, JSONException {
- // Renaming a file to an existing directory should fail
- if (destFile.exists() && destFile.isDirectory()) {
- throw new InvalidModificationException("Can't rename a file to a directory");
- }
-
- copyAction(srcFile, destFile);
-
- return getEntry(destFile);
- }
-
- /**
- * Moved this code into it's own method so moveTo could use it when the move is across file systems
- */
- private void copyAction(File srcFile, File destFile)
- throws FileNotFoundException, IOException {
- FileInputStream istream = new FileInputStream(srcFile);
- FileOutputStream ostream = new FileOutputStream(destFile);
- FileChannel input = istream.getChannel();
- FileChannel output = ostream.getChannel();
-
- try {
- input.transferTo(0, input.size(), output);
- } finally {
- istream.close();
- ostream.close();
- input.close();
- output.close();
- }
- }
-
- /**
- * Copy a directory
- *
- * @param srcDir directory to be copied
- * @param destinationDir destination to be copied to
- * @return a DirectoryEntry object
- * @throws JSONException
- * @throws IOException
- * @throws NoModificationAllowedException
- * @throws InvalidModificationException
- */
- private JSONObject copyDirectory(File srcDir, File destinationDir) throws JSONException, IOException, NoModificationAllowedException, InvalidModificationException {
- // Renaming a file to an existing directory should fail
- if (destinationDir.exists() && destinationDir.isFile()) {
- throw new InvalidModificationException("Can't rename a file to a directory");
- }
-
- // Check to make sure we are not copying the directory into itself
- if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
- throw new InvalidModificationException("Can't copy itself into itself");
- }
-
- // See if the destination directory exists. If not create it.
- if (!destinationDir.exists()) {
- if (!destinationDir.mkdir()) {
- // If we can't create the directory then fail
- throw new NoModificationAllowedException("Couldn't create the destination directory");
- }
- }
-
- for (File file : srcDir.listFiles()) {
- if (file.isDirectory()) {
- copyDirectory(file, destinationDir);
- } else {
- File destination = new File(destinationDir.getAbsoluteFile() + File.separator + file.getName());
- copyFile(file, destination);
- }
- }
-
- return getEntry(destinationDir);
- }
-
- /**
- * Check to see if the user attempted to copy an entry into its parent without changing its name,
- * or attempted to copy a directory into a directory that it contains directly or indirectly.
- *
- * @param srcDir
- * @param destinationDir
- * @return
- */
- private boolean isCopyOnItself(String src, String dest) {
-
- // This weird test is to determine if we are copying or moving a directory into itself.
- // Copy /sdcard/myDir to /sdcard/myDir-backup is okay but
- // Copy /sdcard/myDir to /sdcard/myDir/backup should throw an INVALID_MODIFICATION_ERR
- if (dest.startsWith(src) && dest.indexOf(File.separator, src.length() - 1) != -1) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Move a file
- *
- * @param srcFile file to be copied
- * @param destFile destination to be copied to
- * @return a FileEntry object
- * @throws IOException
- * @throws InvalidModificationException
- * @throws JSONException
- */
- private JSONObject moveFile(File srcFile, File destFile) throws IOException, JSONException, InvalidModificationException {
- // Renaming a file to an existing directory should fail
- if (destFile.exists() && destFile.isDirectory()) {
- throw new InvalidModificationException("Can't rename a file to a directory");
- }
-
- // Try to rename the file
- if (!srcFile.renameTo(destFile)) {
- // Trying to rename the file failed. Possibly because we moved across file system on the device.
- // Now we have to do things the hard way
- // 1) Copy all the old file
- // 2) delete the src file
- copyAction(srcFile, destFile);
- if (destFile.exists()) {
- srcFile.delete();
- } else {
- throw new IOException("moved failed");
- }
- }
-
- return getEntry(destFile);
- }
-
- /**
- * Move a directory
- *
- * @param srcDir directory to be copied
- * @param destinationDir destination to be copied to
- * @return a DirectoryEntry object
- * @throws JSONException
- * @throws IOException
- * @throws InvalidModificationException
- * @throws NoModificationAllowedException
- * @throws FileExistsException
- */
- private JSONObject moveDirectory(File srcDir, File destinationDir) throws IOException, JSONException, InvalidModificationException, NoModificationAllowedException, FileExistsException {
- // Renaming a file to an existing directory should fail
- if (destinationDir.exists() && destinationDir.isFile()) {
- throw new InvalidModificationException("Can't rename a file to a directory");
- }
-
- // Check to make sure we are not copying the directory into itself
- if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
- throw new InvalidModificationException("Can't move itself into itself");
- }
-
- // If the destination directory already exists and is empty then delete it. This is according to spec.
- if (destinationDir.exists()) {
- if (destinationDir.list().length > 0) {
- throw new InvalidModificationException("directory is not empty");
- }
- }
-
- // Try to rename the directory
- if (!srcDir.renameTo(destinationDir)) {
- // Trying to rename the directory failed. Possibly because we moved across file system on the device.
- // Now we have to do things the hard way
- // 1) Copy all the old files
- // 2) delete the src directory
- copyDirectory(srcDir, destinationDir);
- if (destinationDir.exists()) {
- removeDirRecursively(srcDir);
- } else {
- throw new IOException("moved failed");
- }
- }
-
- return getEntry(destinationDir);
- }
-
- /**
- * Deletes a directory and all of its contents, if any. In the event of an error
- * [e.g. trying to delete a directory that contains a file that cannot be removed],
- * some of the contents of the directory may be deleted.
- * It is an error to attempt to delete the root directory of a filesystem.
- *
- * @param filePath the directory to be removed
- * @return a boolean representing success of failure
- * @throws FileExistsException
- */
- private boolean removeRecursively(String filePath) throws FileExistsException {
- File fp = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.readEntries").getRealFile();
-
- // You can't delete the root directory.
- if (atRootDirectory(filePath)) {
- return false;
- }
-
- return removeDirRecursively(fp);
- }
-
- /**
- * Loops through a directory deleting all the files.
- *
- * @param directory to be removed
- * @return a boolean representing success of failure
- * @throws FileExistsException
- */
- private boolean removeDirRecursively(File directory) throws FileExistsException {
- if (directory.isDirectory()) {
- for (File file : directory.listFiles()) {
- removeDirRecursively(file);
- }
- }
-
- if (!directory.delete()) {
- throw new FileExistsException("could not delete: " + directory.getName());
- } else {
- return true;
- }
- }
-
- /**
- * Deletes a file or directory. It is an error to attempt to delete a directory that is not empty.
- * It is an error to attempt to delete the root directory of a filesystem.
- *
- * @param filePath file or directory to be removed
- * @return a boolean representing success of failure
- * @throws NoModificationAllowedException
- * @throws InvalidModificationException
- */
- private boolean remove(String filePath) throws NoModificationAllowedException, InvalidModificationException {
- File fp = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.readEntries").getRealFile();
-
- // You can't delete the root directory.
- if (atRootDirectory(filePath)) {
- throw new NoModificationAllowedException("You can't delete the root directory");
- }
-
- // You can't delete a directory that is not empty
- if (fp.isDirectory() && fp.list().length > 0) {
- throw new InvalidModificationException("You can't delete a directory that is not empty.");
- }
-
- return fp.delete();
- }
-
- /**
- * Creates or looks up a file.
- *
- * @param dirPath base directory
- * @param fileName file/directory to lookup or create
- * @param options specify whether to create or not
- * @param directory if true look up directory, if false look up file
- * @return a Entry object
- * @throws FileExistsException
- * @throws IOException
- * @throws TypeMismatchException
- * @throws EncodingException
- * @throws JSONException
- */
- private JSONObject getFile(String dirPath, String fileName, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
- boolean create = false;
- boolean exclusive = false;
- if (options != null) {
- create = options.optBoolean("create");
- if (create) {
- exclusive = options.optBoolean("exclusive");
- }
- }
-
- // Check for a ":" character in the file to line up with BB and iOS
- if (fileName.contains(":")) {
- throw new EncodingException("This file has a : in it's name");
- }
-
- String filePath = getFullFilePath(dirPath, fileName);
- File fp = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getFile").getRealFile();
-
- if (create) {
- if (exclusive && fp.exists()) {
- throw new FileExistsException("create/exclusive fails");
- }
- if (directory) {
- fp.mkdir();
- } else {
- fp.createNewFile();
- }
- if (!fp.exists()) {
- throw new FileExistsException("create fails");
- }
- }
- else {
- if (!fp.exists()) {
- throw new FileNotFoundException("path does not exist");
- }
- if (directory) {
- if (fp.isFile()) {
- throw new TypeMismatchException("path doesn't exist or is file");
- }
- } else {
- if (fp.isDirectory()) {
- throw new TypeMismatchException("path doesn't exist or is directory");
- }
- }
- }
-
- // Return the directory
- return getEntry(fp);
- }
-
- /**
- * If the path starts with a '/' just return that file object. If not construct the file
- * object from the path passed in and the file name.
- *
- * @param dirPath root directory
- * @param fileName new file name
- * @return
- */
- private String getFullFilePath(String dirPath, String fileName) {
- if (fileName.startsWith("/")) {
- return fileName;
- } else {
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(dirPath, webView.pluginManager, cordova, "FileUtils.getFullFilePath");
- dirPath = dataResource.getRealFile().getPath();
- return dirPath + File.separator + fileName;
- }
- }
-
- /**
- * Look up the parent DirectoryEntry containing this Entry.
- * If this Entry is the root of its filesystem, its parent is itself.
- *
- * @param filePath
- * @return
- * @throws JSONException
- */
- private JSONObject getParent(String filePath) throws JSONException {
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getParent");
- filePath = dataResource.getRealFile().getPath();
-
- if (atRootDirectory(filePath)) {
- return getEntry(filePath);
- }
- return getEntry(dataResource.getRealFile().getParent());
- }
-
- /**
- * Checks to see if we are at the root directory. Useful since we are
- * not allow to delete this directory.
- *
- * @param filePath to directory
- * @return true if we are at the root, false otherwise.
- */
- private boolean atRootDirectory(String filePath) {
- filePath = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.atRootDirectory").getRealFile().getPath();
-
- if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + cordova.getActivity().getPackageName() + "/cache") ||
- filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
- filePath.equals("/data/data/" + cordova.getActivity().getPackageName())) {
- return true;
- }
- return false;
- }
-
- /**
- * Look up metadata about this entry.
- *
- * @param filePath to entry
- * @return a long
- * @throws FileNotFoundException
- */
- private long getMetadata(String filePath) throws FileNotFoundException {
- File file = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getMetadata").getRealFile();
-
- if (file == null || !file.exists()) {
- throw new FileNotFoundException("Failed to find file in getMetadata");
- }
-
- return file.lastModified();
- }
-
- /**
- * Returns a File that represents the current state of the file that this FileEntry represents.
- *
- * @param filePath to entry
- * @return returns a JSONObject represent a W3C File object
- * @throws FileNotFoundException
- * @throws JSONException
- */
- private JSONObject getFileMetadata(String filePath) throws FileNotFoundException, JSONException {
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getMetadata");
- File file = dataResource.getRealFile();
-
- if (file == null || !file.exists()) {
- throw new FileNotFoundException("File: " + filePath + " does not exist.");
- }
-
- JSONObject metadata = new JSONObject();
- metadata.put("size", file.length());
- metadata.put("type", dataResource.getMimeType());
- metadata.put("name", file.getName());
- metadata.put("fullPath", filePath);
- metadata.put("lastModifiedDate", file.lastModified());
-
- return metadata;
- }
-
- /**
- * Requests a filesystem in which to store application data.
- *
- * @param type of file system requested
- * @return a JSONObject representing the file system
- * @throws IOException
- * @throws JSONException
- */
- private JSONObject requestFileSystem(int type) throws IOException, JSONException {
- JSONObject fs = new JSONObject();
- if (type == TEMPORARY) {
- File fp;
- fs.put("name", "temporary");
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- fp = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
- "/Android/data/" + cordova.getActivity().getPackageName() + "/cache/");
- // Create the cache dir if it doesn't exist.
- fp.mkdirs();
- fs.put("root", getEntry(Environment.getExternalStorageDirectory().getAbsolutePath() +
- "/Android/data/" + cordova.getActivity().getPackageName() + "/cache/"));
- } else {
- fp = new File("/data/data/" + cordova.getActivity().getPackageName() + "/cache/");
- // Create the cache dir if it doesn't exist.
- fp.mkdirs();
- fs.put("root", getEntry("/data/data/" + cordova.getActivity().getPackageName() + "/cache/"));
- }
- }
- else if (type == PERSISTENT) {
- fs.put("name", "persistent");
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- fs.put("root", getEntry(Environment.getExternalStorageDirectory()));
- } else {
- fs.put("root", getEntry("/data/data/" + cordova.getActivity().getPackageName()));
- }
- }
- else {
- throw new IOException("No filesystem of type requested");
- }
-
- return fs;
- }
-
- /**
- * Returns a JSON object representing the given File.
- *
- * @param file the File to convert
- * @return a JSON representation of the given File
- * @throws JSONException
- */
- public static JSONObject getEntry(File file) throws JSONException {
- JSONObject entry = new JSONObject();
-
- entry.put("isFile", file.isFile());
- entry.put("isDirectory", file.isDirectory());
- entry.put("name", file.getName());
- entry.put("fullPath", "file://" + file.getAbsolutePath());
- // The file system can't be specified, as it would lead to an infinite loop.
- // entry.put("filesystem", null);
-
- return entry;
- }
-
- /**
- * Returns a JSON Object representing a directory on the device's file system
- *
- * @param path to the directory
- * @return
- * @throws JSONException
- */
- private JSONObject getEntry(String path) throws JSONException {
- return getEntry(new File(path));
- }
-
-
- //--------------------------------------------------------------------------
- // LOCAL METHODS
- //--------------------------------------------------------------------------
-
- /**
- * Read the contents of a file.
- * This is done in a background thread; the result is sent to the callback.
- *
- * @param filename The name of the file.
- * @param start Start position in the file.
- * @param end End position to stop at (exclusive).
- * @param callbackContext The context through which to send the result.
- * @param encoding The encoding to return contents as. Typical value is UTF-8. (see http://www.iana.org/assignments/character-sets)
- * @param resultType The desired type of data to send to the callback.
- * @return Contents of file.
- */
- public void readFileAs(final String filename, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) {
- this.cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- try {
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.readFileAs");
- byte[] bytes = readAsBinaryHelper(dataResource.getInputStream(), start, end);
-
- PluginResult result;
- switch (resultType) {
- case PluginResult.MESSAGE_TYPE_STRING:
- result = new PluginResult(PluginResult.Status.OK, new String(bytes, encoding));
- break;
- case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
- result = new PluginResult(PluginResult.Status.OK, bytes);
- break;
- case PluginResult.MESSAGE_TYPE_BINARYSTRING:
- result = new PluginResult(PluginResult.Status.OK, bytes, true);
- break;
- default: // Base64.
- String contentType = dataResource.getMimeType();
- byte[] base64 = Base64.encodeBase64(bytes);
- String s = "data:" + contentType + ";base64," + new String(base64, "US-ASCII");
- result = new PluginResult(PluginResult.Status.OK, s);
- }
-
- callbackContext.sendPluginResult(result);
- } catch (FileNotFoundException e) {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_FOUND_ERR));
- } catch (IOException e) {
- Log.d(LOG_TAG, e.getLocalizedMessage());
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_READABLE_ERR));
- }
- }
- });
- }
-
- /**
- * Read the contents of a file as binary.
- * This is done synchronously; the result is returned.
- *
- * @param filename The name of the file.
- * @param start Start position in the file.
- * @param end End position to stop at (exclusive).
- * @return Contents of the file as a byte[].
- * @throws IOException
- */
- private byte[] readAsBinaryHelper(InputStream inputStream, int start, int end) throws IOException {
- int numBytesToRead = end - start;
- byte[] bytes = new byte[numBytesToRead];
- int numBytesRead = 0;
-
- if (start > 0) {
- inputStream.skip(start);
- }
-
- while (numBytesToRead > 0 && (numBytesRead = inputStream.read(bytes, numBytesRead, numBytesToRead)) >= 0) {
- numBytesToRead -= numBytesRead;
- }
-
- return bytes;
- }
-
- /**
- * Write contents of file.
- *
- * @param filename The name of the file.
- * @param data The contents of the file.
- * @param offset The position to begin writing the file.
- * @throws FileNotFoundException, IOException
- * @throws NoModificationAllowedException
- */
- /**/
- public long write(String filename, String data, int offset) throws FileNotFoundException, IOException, NoModificationAllowedException {
- if (filename.startsWith("content://")) {
- throw new NoModificationAllowedException("Couldn't write to file given its content URI");
- }
-
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.write");
- filename = dataResource.getRealFile().getPath();
-
- boolean append = false;
- if (offset > 0) {
- this.truncateFile(filename, offset);
- append = true;
- }
-
- byte[] rawData = data.getBytes();
- ByteArrayInputStream in = new ByteArrayInputStream(rawData);
- FileOutputStream out = new FileOutputStream(filename, append);
- byte buff[] = new byte[rawData.length];
- in.read(buff, 0, buff.length);
- out.write(buff, 0, rawData.length);
- out.flush();
- out.close();
-
- return rawData.length;
- }
-
- /**
- * Truncate the file to size
- *
- * @param filename
- * @param size
- * @throws FileNotFoundException, IOException
- * @throws NoModificationAllowedException
- */
- private long truncateFile(String filename, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
- DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.truncateFile");
- if(!dataResource.isWritable()) {
- throw new NoModificationAllowedException("Couldn't truncate file as it is not writable");
- }
- File file = dataResource.getRealFile();
- if(file == null) {
- throw new FileNotFoundException("Couldn't get the file");
- }
-
- RandomAccessFile raf = new RandomAccessFile(file, "rw");
- try {
- if (raf.length() >= size) {
- FileChannel channel = raf.getChannel();
- channel.truncate(size);
- return size;
- }
-
- return raf.length();
- } finally {
- raf.close();
- }
- }
-}
diff --git a/framework/src/org/apache/cordova/GPSListener.java b/framework/src/org/apache/cordova/GPSListener.java
deleted file mode 100755
index daaf7eeb..00000000
--- a/framework/src/org/apache/cordova/GPSListener.java
+++ /dev/null
@@ -1,50 +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 org.apache.cordova;
-
-import android.location.LocationManager;
-
-/**
- * This class handles requests for GPS location services.
- *
- */
-public class GPSListener extends CordovaLocationListener {
- public GPSListener(LocationManager locationManager, GeoBroker m) {
- super(locationManager, m, "[Cordova GPSListener]");
- }
-
-
- /**
- * Start requesting location updates.
- *
- * @param interval
- */
- @Override
- protected void start() {
- if (!this.running) {
- if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
- this.running = true;
- this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this);
- } else {
- this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available.");
- }
- }
- }
-}
diff --git a/framework/src/org/apache/cordova/GeoBroker.java b/framework/src/org/apache/cordova/GeoBroker.java
deleted file mode 100644
index 4a07b738..00000000
--- a/framework/src/org/apache/cordova/GeoBroker.java
+++ /dev/null
@@ -1,206 +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 org.apache.cordova;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.content.Context;
-import android.location.Location;
-import android.location.LocationManager;
-
-/*
- * 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 CordovaPlugin {
- private GPSListener gpsListener;
- private NetworkListener networkListener;
- private LocationManager locationManager;
-
- /**
- * Constructor.
- */
- public GeoBroker() {
- }
-
- /**
- * Executes the request and returns PluginResult.
- *
- * @param action The action to execute.
- * @param args JSONArry of arguments for the plugin.
- * @param callbackContext The callback id used when calling back into JavaScript.
- * @return True if the action was valid, or false if not.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- if (this.locationManager == null) {
- this.locationManager = (LocationManager) this.cordova.getActivity().getSystemService(Context.LOCATION_SERVICE);
- this.networkListener = new NetworkListener(this.locationManager, this);
- this.gpsListener = new GPSListener(this.locationManager, this);
- }
-
- if ( locationManager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ||
- locationManager.isProviderEnabled( LocationManager.NETWORK_PROVIDER )) {
-
- if (action.equals("getLocation")) {
- boolean enableHighAccuracy = args.getBoolean(0);
- int maximumAge = args.getInt(1);
- Location last = this.locationManager.getLastKnownLocation((enableHighAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER));
- // Check if we can use lastKnownLocation to get a quick reading and use less battery
- if (last != null && (System.currentTimeMillis() - last.getTime()) <= maximumAge) {
- PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(last));
- callbackContext.sendPluginResult(result);
- } else {
- this.getCurrentLocation(callbackContext, enableHighAccuracy, args.optInt(2, 60000));
- }
- }
- else if (action.equals("addWatch")) {
- String id = args.getString(0);
- boolean enableHighAccuracy = args.getBoolean(1);
- this.addWatch(id, callbackContext, enableHighAccuracy);
- }
- else if (action.equals("clearWatch")) {
- String id = args.getString(0);
- this.clearWatch(id);
- }
- else {
- return false;
- }
- } else {
- PluginResult.Status status = PluginResult.Status.NO_RESULT;
- String message = "Location API is not available for this device.";
- PluginResult result = new PluginResult(status, message);
- callbackContext.sendPluginResult(result);
- }
- return true;
- }
-
- private void clearWatch(String id) {
- this.gpsListener.clearWatch(id);
- this.networkListener.clearWatch(id);
- }
-
- private void getCurrentLocation(CallbackContext callbackContext, boolean enableHighAccuracy, int timeout) {
- if (enableHighAccuracy) {
- this.gpsListener.addCallback(callbackContext, timeout);
- } else {
- this.networkListener.addCallback(callbackContext, timeout);
- }
- }
-
- private void addWatch(String timerId, CallbackContext callbackContext, boolean enableHighAccuracy) {
- if (enableHighAccuracy) {
- this.gpsListener.addWatch(timerId, callbackContext);
- } else {
- this.networkListener.addWatch(timerId, callbackContext);
- }
- }
-
- /**
- * Called when the activity is to be shut down.
- * Stop listener.
- */
- public void onDestroy() {
- if (this.networkListener != null) {
- this.networkListener.destroy();
- this.networkListener = null;
- }
- if (this.gpsListener != null) {
- this.gpsListener.destroy();
- this.gpsListener = null;
- }
- }
-
- /**
- * Called when the view navigates.
- * Stop the listeners.
- */
- public void onReset() {
- this.onDestroy();
- }
-
- public JSONObject returnLocationJSON(Location loc) {
- JSONObject o = new JSONObject();
-
- try {
- o.put("latitude", loc.getLatitude());
- o.put("longitude", loc.getLongitude());
- o.put("altitude", (loc.hasAltitude() ? loc.getAltitude() : null));
- o.put("accuracy", loc.getAccuracy());
- o.put("heading", (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : null) : null));
- o.put("velocity", loc.getSpeed());
- o.put("timestamp", loc.getTime());
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- return o;
- }
-
- public void win(Location loc, CallbackContext callbackContext, boolean keepCallback) {
- PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
- result.setKeepCallback(keepCallback);
- callbackContext.sendPluginResult(result);
- }
-
- /**
- * Location failed. Send error back to JavaScript.
- *
- * @param code The error code
- * @param msg The error message
- * @throws JSONException
- */
- public void fail(int code, String msg, CallbackContext callbackContext, boolean keepCallback) {
- JSONObject obj = new JSONObject();
- String backup = null;
- try {
- obj.put("code", code);
- obj.put("message", msg);
- } catch (JSONException e) {
- obj = null;
- backup = "{'code':" + code + ",'message':'" + msg.replaceAll("'", "\'") + "'}";
- }
- PluginResult result;
- if (obj != null) {
- result = new PluginResult(PluginResult.Status.ERROR, obj);
- } else {
- result = new PluginResult(PluginResult.Status.ERROR, backup);
- }
-
- result.setKeepCallback(keepCallback);
- callbackContext.sendPluginResult(result);
- }
-
- public boolean isGlobalListener(CordovaLocationListener listener)
- {
- if (gpsListener != null && networkListener != null)
- {
- return gpsListener.equals(listener) || networkListener.equals(listener);
- }
- else
- return false;
- }
-}
diff --git a/framework/src/org/apache/cordova/Globalization.java b/framework/src/org/apache/cordova/Globalization.java
deleted file mode 100644
index 5c75e100..00000000
--- a/framework/src/org/apache/cordova/Globalization.java
+++ /dev/null
@@ -1,577 +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 org.apache.cordova;
-
-import java.text.DateFormat;
-import java.text.DecimalFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Currency;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.annotation.TargetApi;
-import android.text.format.Time;
-
-/**
- *
- */
-public class Globalization extends CordovaPlugin {
- //GlobalizationCommand Plugin Actions
- public static final String GETLOCALENAME = "getLocaleName";
- public static final String DATETOSTRING = "dateToString";
- public static final String STRINGTODATE = "stringToDate";
- public static final String GETDATEPATTERN = "getDatePattern";
- public static final String GETDATENAMES = "getDateNames";
- public static final String ISDAYLIGHTSAVINGSTIME = "isDayLightSavingsTime";
- public static final String GETFIRSTDAYOFWEEK = "getFirstDayOfWeek";
- public static final String NUMBERTOSTRING = "numberToString";
- public static final String STRINGTONUMBER = "stringToNumber";
- public static final String GETNUMBERPATTERN = "getNumberPattern";
- public static final String GETCURRENCYPATTERN = "getCurrencyPattern";
- public static final String GETPREFERREDLANGUAGE = "getPreferredLanguage";
-
- //GlobalizationCommand Option Parameters
- public static final String OPTIONS = "options";
- public static final String FORMATLENGTH = "formatLength";
- //public static final String SHORT = "short"; //default for dateToString format
- public static final String MEDIUM = "medium";
- public static final String LONG = "long";
- public static final String FULL = "full";
- public static final String SELECTOR = "selector";
- //public static final String DATEANDTIME = "date and time"; //default for dateToString
- public static final String DATE = "date";
- public static final String TIME = "time";
- public static final String DATESTRING = "dateString";
- public static final String TYPE = "type";
- public static final String ITEM = "item";
- public static final String NARROW = "narrow";
- public static final String WIDE = "wide";
- public static final String MONTHS = "months";
- public static final String DAYS = "days";
- //public static final String DECMIAL = "wide"; //default for numberToString
- public static final String NUMBER = "number";
- public static final String NUMBERSTRING = "numberString";
- public static final String PERCENT = "percent";
- public static final String CURRENCY = "currency";
- public static final String CURRENCYCODE = "currencyCode";
-
- @Override
- public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
- JSONObject obj = new JSONObject();
-
- try{
- if (action.equals(GETLOCALENAME)){
- obj = getLocaleName();
- }else if (action.equals(GETPREFERREDLANGUAGE)){
- obj = getPreferredLanguage();
- } else if (action.equalsIgnoreCase(DATETOSTRING)) {
- obj = getDateToString(data);
- }else if(action.equalsIgnoreCase(STRINGTODATE)){
- obj = getStringtoDate(data);
- }else if(action.equalsIgnoreCase(GETDATEPATTERN)){
- obj = getDatePattern(data);
- }else if(action.equalsIgnoreCase(GETDATENAMES)){
- if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.GINGERBREAD) {
- throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
- } else {
- obj = getDateNames(data);
- }
- }else if(action.equalsIgnoreCase(ISDAYLIGHTSAVINGSTIME)){
- obj = getIsDayLightSavingsTime(data);
- }else if(action.equalsIgnoreCase(GETFIRSTDAYOFWEEK)){
- obj = getFirstDayOfWeek(data);
- }else if(action.equalsIgnoreCase(NUMBERTOSTRING)){
- obj = getNumberToString(data);
- }else if(action.equalsIgnoreCase(STRINGTONUMBER)){
- obj = getStringToNumber(data);
- }else if(action.equalsIgnoreCase(GETNUMBERPATTERN)){
- obj = getNumberPattern(data);
- }else if(action.equalsIgnoreCase(GETCURRENCYPATTERN)){
- obj = getCurrencyPattern(data);
- }else {
- return false;
- }
-
- callbackContext.success(obj);
- }catch (GlobalizationError ge){
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, ge.toJson()));
- }catch (Exception e){
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
- }
- return true;
- }
- /*
- * @Description: Returns the string identifier for the client's current locale setting
- *
- * @Return: JSONObject
- * Object.value {String}: The locale identifier
- *
- * @throws: GlobalizationError.UNKNOWN_ERROR
- */
- private JSONObject getLocaleName() throws GlobalizationError{
- JSONObject obj = new JSONObject();
- try{
- obj.put("value",Locale.getDefault().toString());//get the locale from the Android Device
- return obj;
- }catch(Exception e){
- throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
- }
- }
- /*
- * @Description: Returns the string identifier for the client's current language
- *
- * @Return: JSONObject
- * Object.value {String}: The language identifier
- *
- * @throws: GlobalizationError.UNKNOWN_ERROR
- */
- private JSONObject getPreferredLanguage() throws GlobalizationError {
- JSONObject obj = new JSONObject();
- try {
- obj.put("value", Locale.getDefault().getDisplayLanguage().toString());
- return obj;
- } catch (Exception e) {
- throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
- }
- }
- /*
- * @Description: Returns a date formatted as a string according to the client's user preferences and
- * calendar using the time zone of the client.
- *
- * @Return: JSONObject
- * Object.value {String}: The localized date string
- *
- * @throws: GlobalizationError.FORMATTING_ERROR
- */
- private JSONObject getDateToString(JSONArray options) throws GlobalizationError{
- JSONObject obj = new JSONObject();
- try{
- Date date = new Date((Long)options.getJSONObject(0).get(DATE));
-
- //get formatting pattern from android device (Will only have device specific formatting for short form of date) or options supplied
- JSONObject datePattern = getDatePattern(options);
- SimpleDateFormat fmt = new SimpleDateFormat(datePattern.getString("pattern"));
-
- //return formatted date
- return obj.put("value",fmt.format(date));
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
- }
- }
-
- /*
- * @Description: Parses a date formatted as a string according to the client's user
- * preferences and calendar using the time zone of the client and returns
- * the corresponding date object
- * @Return: JSONObject
- * Object.year {Number}: The four digit year
- * Object.month {Number}: The month from (0 - 11)
- * Object.day {Number}: The day from (1 - 31)
- * Object.hour {Number}: The hour from (0 - 23)
- * Object.minute {Number}: The minute from (0 - 59)
- * Object.second {Number}: The second from (0 - 59)
- * Object.millisecond {Number}: The milliseconds (from 0 - 999), not available on all platforms
- *
- * @throws: GlobalizationError.PARSING_ERROR
- */
- private JSONObject getStringtoDate(JSONArray options)throws GlobalizationError{
- JSONObject obj = new JSONObject();
- Date date;
- try{
- //get format pattern from android device (Will only have device specific formatting for short form of date) or options supplied
- DateFormat fmt = new SimpleDateFormat(getDatePattern(options).getString("pattern"));
-
- //attempt parsing string based on user preferences
- date = fmt.parse(options.getJSONObject(0).get(DATESTRING).toString());
-
- //set Android Time object
- Time time = new Time();
- time.set(date.getTime());
-
- //return properties;
- obj.put("year", time.year);
- obj.put("month", time.month);
- obj.put("day", time.monthDay);
- obj.put("hour", time.hour);
- obj.put("minute", time.minute);
- obj.put("second", time.second);
- obj.put("millisecond", new Long(0));
- return obj;
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.PARSING_ERROR);
- }
- }
-
- /*
- * @Description: Returns a pattern string for formatting and parsing dates according to the client's
- * user preferences.
- * @Return: JSONObject
- *
- * Object.pattern {String}: The date and time pattern for formatting and parsing dates.
- * The patterns follow Unicode Technical Standard #35
- * http://unicode.org/reports/tr35/tr35-4.html
- * Object.timezone {String}: The abbreviated name of the time zone on the client
- * Object.utc_offset {Number}: The current difference in seconds between the client's
- * time zone and coordinated universal time.
- * Object.dst_offset {Number}: The current daylight saving time offset in seconds
- * between the client's non-daylight saving's time zone
- * and the client's daylight saving's time zone.
- *
- * @throws: GlobalizationError.PATTERN_ERROR
- */
- private JSONObject getDatePattern(JSONArray options) throws GlobalizationError{
- JSONObject obj = new JSONObject();
-
- try{
- SimpleDateFormat fmtDate = (SimpleDateFormat)android.text.format.DateFormat.getDateFormat(this.cordova.getActivity()); //default user preference for date
- SimpleDateFormat fmtTime = (SimpleDateFormat)android.text.format.DateFormat.getTimeFormat(this.cordova.getActivity()); //default user preference for time
-
- String fmt = fmtDate.toLocalizedPattern() + " " + fmtTime.toLocalizedPattern(); //default SHORT date/time format. ex. dd/MM/yyyy h:mm a
-
- //get Date value + options (if available)
- if (options.getJSONObject(0).length() > 1){
- //options were included
-
- //get formatLength option
- if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(FORMATLENGTH)){
- String fmtOpt = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(FORMATLENGTH);
- if (fmtOpt.equalsIgnoreCase(MEDIUM)){//medium
- fmtDate = (SimpleDateFormat)android.text.format.DateFormat.getMediumDateFormat(this.cordova.getActivity());
- }else if (fmtOpt.equalsIgnoreCase(LONG) || fmtOpt.equalsIgnoreCase(FULL)){ //long/full
- fmtDate = (SimpleDateFormat)android.text.format.DateFormat.getLongDateFormat(this.cordova.getActivity());
- }
- }
-
- //return pattern type
- fmt = fmtDate.toLocalizedPattern() + " " + fmtTime.toLocalizedPattern();
- if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(SELECTOR)){
- String selOpt = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(SELECTOR);
- if (selOpt.equalsIgnoreCase(DATE)){
- fmt = fmtDate.toLocalizedPattern();
- }else if (selOpt.equalsIgnoreCase(TIME)){
- fmt = fmtTime.toLocalizedPattern();
- }
- }
- }
-
- //TimeZone from users device
- //TimeZone tz = Calendar.getInstance(Locale.getDefault()).getTimeZone(); //substitute method
- TimeZone tz = TimeZone.getTimeZone(Time.getCurrentTimezone());
-
- obj.put("pattern", fmt);
- obj.put("timezone", tz.getDisplayName(tz.inDaylightTime(Calendar.getInstance().getTime()),TimeZone.SHORT));
- obj.put("utc_offset", tz.getRawOffset()/1000);
- obj.put("dst_offset", tz.getDSTSavings()/1000);
- return obj;
-
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.PATTERN_ERROR);
- }
- }
-
- /*
- * @Description: Returns an array of either the names of the months or days of the week
- * according to the client's user preferences and calendar
- * @Return: JSONObject
- * Object.value {Array{String}}: The array of names starting from either
- * the first month in the year or the
- * first day of the week.
- *
- * @throws: GlobalizationError.UNKNOWN_ERROR
- */
- @TargetApi(9)
- private JSONObject getDateNames(JSONArray options) throws GlobalizationError{
- JSONObject obj = new JSONObject();
- //String[] value;
- JSONArray value = new JSONArray();
- List namesList = new ArrayList();
- final Map namesMap; // final needed for sorting with anonymous comparator
- try{
- int type = 0; //default wide
- int item = 0; //default months
-
- //get options if available
- if (options.getJSONObject(0).length() > 0){
- //get type if available
- if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(TYPE)){
- String t = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(TYPE);
- if (t.equalsIgnoreCase(NARROW)){type++;} //DateUtils.LENGTH_MEDIUM
- }
- //get item if available
- if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(ITEM)){
- String t = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(ITEM);
- if (t.equalsIgnoreCase(DAYS)){item += 10;} //Days of week start at 1
- }
- }
- //determine return value
- int method = item + type;
- if (method == 1) { //months and narrow
- namesMap = Calendar.getInstance().getDisplayNames(Calendar.MONTH, Calendar.SHORT, Locale.getDefault());
- } else if (method == 10) { //days and wide
- namesMap = Calendar.getInstance().getDisplayNames(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault());
- } else if (method == 11) { //days and narrow
- namesMap = Calendar.getInstance().getDisplayNames(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.getDefault());
- } else { //default: months and wide
- namesMap = Calendar.getInstance().getDisplayNames(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
- }
-
- // save names as a list
- for(String name : namesMap.keySet()) {
- namesList.add(name);
- }
-
- // sort the list according to values in namesMap
- Collections.sort(namesList, new Comparator() {
- public int compare(String arg0, String arg1) {
- return namesMap.get(arg0).compareTo(namesMap.get(arg1));
- }
- });
-
- // convert nameList into JSONArray of String objects
- for (int i = 0; i < namesList.size(); i ++){
- value.put(namesList.get(i));
- }
-
- //return array of names
- return obj.put("value", value);
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
- }
- }
-
- /*
- * @Description: Returns whether daylight savings time is in effect for a given date using the client's
- * time zone and calendar.
- * @Return: JSONObject
- * Object.dst {Boolean}: The value "true" indicates that daylight savings time is
- * in effect for the given date and "false" indicate that it is not. *
- *
- * @throws: GlobalizationError.UNKNOWN_ERROR
- */
- private JSONObject getIsDayLightSavingsTime(JSONArray options) throws GlobalizationError{
- JSONObject obj = new JSONObject();
- boolean dst = false;
- try{
- Date date = new Date((Long)options.getJSONObject(0).get(DATE));
- //TimeZone tz = Calendar.getInstance(Locale.getDefault()).getTimeZone();
- TimeZone tz = TimeZone.getTimeZone(Time.getCurrentTimezone());
- dst = tz.inDaylightTime(date); //get daylight savings data from date object and user timezone settings
-
- return obj.put("dst",dst);
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
- }
- }
-
- /*
- * @Description: Returns the first day of the week according to the client's user preferences and calendar.
- * The days of the week are numbered starting from 1 where 1 is considered to be Sunday.
- * @Return: JSONObject
- * Object.value {Number}: The number of the first day of the week.
- *
- * @throws: GlobalizationError.UNKNOWN_ERROR
- */
- private JSONObject getFirstDayOfWeek(JSONArray options) throws GlobalizationError{
- JSONObject obj = new JSONObject();
- try{
- int value = Calendar.getInstance(Locale.getDefault()).getFirstDayOfWeek(); //get first day of week based on user locale settings
- return obj.put("value", value);
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
- }
- }
-
- /*
- * @Description: Returns a number formatted as a string according to the client's user preferences.
- * @Return: JSONObject
- * Object.value {String}: The formatted number string.
- *
- * @throws: GlobalizationError.FORMATTING_ERROR
- */
- private JSONObject getNumberToString(JSONArray options) throws GlobalizationError{
- JSONObject obj = new JSONObject();
- String value = "";
- try{
- DecimalFormat fmt = getNumberFormatInstance(options);//returns Decimal/Currency/Percent instance
- value = fmt.format(options.getJSONObject(0).get(NUMBER));
- return obj.put("value", value);
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
- }
- }
-
- /*
- * @Description: Parses a number formatted as a string according to the client's user preferences and
- * returns the corresponding number.
- * @Return: JSONObject
- * Object.value {Number}: The parsed number.
- *
- * @throws: GlobalizationError.PARSING_ERROR
- */
- private JSONObject getStringToNumber(JSONArray options) throws GlobalizationError{
- JSONObject obj = new JSONObject();
- Number value;
- try{
- DecimalFormat fmt = getNumberFormatInstance(options); //returns Decimal/Currency/Percent instance
- value = fmt.parse((String)options.getJSONObject(0).get(NUMBERSTRING));
- return obj.put("value", value);
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.PARSING_ERROR);
- }
- }
-
- /*
- * @Description: Returns a pattern string for formatting and parsing numbers according to the client's user
- * preferences.
- * @Return: JSONObject
- * Object.pattern {String}: The number pattern for formatting and parsing numbers.
- * The patterns follow Unicode Technical Standard #35.
- * http://unicode.org/reports/tr35/tr35-4.html
- * Object.symbol {String}: The symbol to be used when formatting and parsing
- * e.g., percent or currency symbol.
- * Object.fraction {Number}: The number of fractional digits to use when parsing and
- * formatting numbers.
- * Object.rounding {Number}: The rounding increment to use when parsing and formatting.
- * Object.positive {String}: The symbol to use for positive numbers when parsing and formatting.
- * Object.negative: {String}: The symbol to use for negative numbers when parsing and formatting.
- * Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
- * Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
- *
- * @throws: GlobalizationError.PATTERN_ERROR
- */
- private JSONObject getNumberPattern(JSONArray options) throws GlobalizationError{
- JSONObject obj = new JSONObject();
- try{
- //uses java.text.DecimalFormat to format value
- DecimalFormat fmt = (DecimalFormat) DecimalFormat.getInstance(Locale.getDefault()); //default format
- String symbol = String.valueOf(fmt.getDecimalFormatSymbols().getDecimalSeparator());
- //get Date value + options (if available)
- if (options.getJSONObject(0).length() > 0){
- //options were included
- if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(TYPE)){
- String fmtOpt = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(TYPE);
- if (fmtOpt.equalsIgnoreCase(CURRENCY)){
- fmt = (DecimalFormat) DecimalFormat.getCurrencyInstance(Locale.getDefault());
- symbol = fmt.getDecimalFormatSymbols().getCurrencySymbol();
- }else if(fmtOpt.equalsIgnoreCase(PERCENT)){
- fmt = (DecimalFormat) DecimalFormat.getPercentInstance(Locale.getDefault());
- symbol = String.valueOf(fmt.getDecimalFormatSymbols().getPercent());
- }
- }
- }
-
- //return properties
- obj.put("pattern", fmt.toPattern());
- obj.put("symbol", symbol);
- obj.put("fraction", fmt.getMinimumFractionDigits());
- obj.put("rounding", new Integer(0));
- obj.put("positive", fmt.getPositivePrefix());
- obj.put("negative", fmt.getNegativePrefix());
- obj.put("decimal", String.valueOf(fmt.getDecimalFormatSymbols().getDecimalSeparator()));
- obj.put("grouping", String.valueOf(fmt.getDecimalFormatSymbols().getGroupingSeparator()));
-
- return obj;
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.PATTERN_ERROR);
- }
- }
-
- /*
- * @Description: Returns a pattern string for formatting and parsing currency values according to the client's
- * user preferences and ISO 4217 currency code.
- * @Return: JSONObject
- * Object.pattern {String}: The currency pattern for formatting and parsing currency values.
- * The patterns follow Unicode Technical Standard #35
- * http://unicode.org/reports/tr35/tr35-4.html
- * Object.code {String}: The ISO 4217 currency code for the pattern.
- * Object.fraction {Number}: The number of fractional digits to use when parsing and
- * formatting currency.
- * Object.rounding {Number}: The rounding increment to use when parsing and formatting.
- * Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
- * Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
- *
- * @throws: GlobalizationError.FORMATTING_ERROR
- */
- private JSONObject getCurrencyPattern(JSONArray options) throws GlobalizationError{
- JSONObject obj = new JSONObject();
- try{
- //get ISO 4217 currency code
- String code = options.getJSONObject(0).getString(CURRENCYCODE);
-
- //uses java.text.DecimalFormat to format value
- DecimalFormat fmt = (DecimalFormat) DecimalFormat.getCurrencyInstance(Locale.getDefault());
-
- //set currency format
- Currency currency = Currency.getInstance(code);
- fmt.setCurrency(currency);
-
- //return properties
- obj.put("pattern", fmt.toPattern());
- obj.put("code", currency.getCurrencyCode());
- obj.put("fraction", fmt.getMinimumFractionDigits());
- obj.put("rounding", new Integer(0));
- obj.put("decimal", String.valueOf(fmt.getDecimalFormatSymbols().getDecimalSeparator()));
- obj.put("grouping", String.valueOf(fmt.getDecimalFormatSymbols().getGroupingSeparator()));
-
- return obj;
- }catch(Exception ge){
- throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
- }
- }
-
- /*
- * @Description: Parses a JSONArray from user options and returns the correct Instance of Decimal/Percent/Currency.
- * @Return: DecimalFormat : The Instance to use.
- *
- * @throws: JSONException
- */
- private DecimalFormat getNumberFormatInstance(JSONArray options) throws JSONException{
- DecimalFormat fmt = (DecimalFormat)DecimalFormat.getInstance(Locale.getDefault()); //default format
- try{
- if (options.getJSONObject(0).length() > 1){
- //options were included
- if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(TYPE)){
- String fmtOpt = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(TYPE);
- if (fmtOpt.equalsIgnoreCase(CURRENCY)){
- fmt = (DecimalFormat)DecimalFormat.getCurrencyInstance(Locale.getDefault());
- }else if(fmtOpt.equalsIgnoreCase(PERCENT)){
- fmt = (DecimalFormat)DecimalFormat.getPercentInstance(Locale.getDefault());
- }
- }
- }
-
- }catch (JSONException je){}
- return fmt;
- }
-}
diff --git a/framework/src/org/apache/cordova/GlobalizationError.java b/framework/src/org/apache/cordova/GlobalizationError.java
deleted file mode 100644
index 8a171d42..00000000
--- a/framework/src/org/apache/cordova/GlobalizationError.java
+++ /dev/null
@@ -1,108 +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 org.apache.cordova;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * @description Exception class representing defined Globalization error codes
- * @Globalization error codes:
- * GlobalizationError.UNKNOWN_ERROR = 0;
- * GlobalizationError.FORMATTING_ERROR = 1;
- * GlobalizationError.PARSING_ERROR = 2;
- * GlobalizationError.PATTERN_ERROR = 3;
- */
-public class GlobalizationError extends Exception{
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- public static final String UNKNOWN_ERROR = "UNKNOWN_ERROR";
- public static final String FORMATTING_ERROR = "FORMATTING_ERROR";
- public static final String PARSING_ERROR = "PARSING_ERROR";
- public static final String PATTERN_ERROR = "PATTERN_ERROR";
-
- int error = 0; //default unknown error thrown
- /**
- * Default constructor
- */
- public GlobalizationError() {}
- /**
- * Create an exception returning an error code
- *
- * @param s
- */
- public GlobalizationError(String s) {
- if (s.equalsIgnoreCase(FORMATTING_ERROR)){
- error = 1;
- }else if (s.equalsIgnoreCase(PARSING_ERROR)){
- error = 2;
- }else if (s.equalsIgnoreCase(PATTERN_ERROR)){
- error = 3;
- }
- }
- /**
- * get error string based on error code
- *
- * @param String msg
- */
- public String getErrorString(){
- String msg = "";
- switch (error){
- case 0:
- msg = UNKNOWN_ERROR;
- break;
- case 1:
- msg = FORMATTING_ERROR;
- break;
- case 2:
- msg = PARSING_ERROR;
- break;
- case 3:
- msg = PATTERN_ERROR;
- break;
- }
- return msg;
- }
- /**
- * get error code
- *
- * @param String msg
- */
- public int getErrorCode(){
- return error;
- }
-
- /**
- * get the json version of this object to return to javascript
- * @return
- */
- public JSONObject toJson() {
- JSONObject obj = new JSONObject();
- try {
- obj.put("code", getErrorCode());
- obj.put("message", getErrorString());
- } catch (JSONException e) {
- // never happens
- }
- return obj;
- }
-}
diff --git a/framework/src/org/apache/cordova/HttpHandler.java b/framework/src/org/apache/cordova/HttpHandler.java
deleted file mode 100755
index 1de8302e..00000000
--- a/framework/src/org/apache/cordova/HttpHandler.java
+++ /dev/null
@@ -1,86 +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 org.apache.cordova;
-
-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();
- }
-}
diff --git a/framework/src/org/apache/cordova/InAppBrowser.java b/framework/src/org/apache/cordova/InAppBrowser.java
deleted file mode 100644
index 8e78baa2..00000000
--- a/framework/src/org/apache/cordova/InAppBrowser.java
+++ /dev/null
@@ -1,813 +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 org.apache.cordova;
-
-import java.util.HashMap;
-import java.util.StringTokenizer;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.LOG;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.net.Uri;
-import android.os.Bundle;
-import android.text.InputType;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.webkit.WebChromeClient;
-import android.webkit.GeolocationPermissions.Callback;
-import android.webkit.JsPromptResult;
-import android.webkit.WebSettings;
-import android.webkit.WebStorage;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-
-@SuppressLint("SetJavaScriptEnabled")
-public class InAppBrowser extends CordovaPlugin {
-
- private static final String NULL = "null";
- protected static final String LOG_TAG = "InAppBrowser";
- private static final String SELF = "_self";
- private static final String SYSTEM = "_system";
- // private static final String BLANK = "_blank";
- private static final String LOCATION = "location";
- private static final String EXIT_EVENT = "exit";
- private static final String LOAD_START_EVENT = "loadstart";
- private static final String LOAD_STOP_EVENT = "loadstop";
- private static final String LOAD_ERROR_EVENT = "loaderror";
- private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption";
- private long MAX_QUOTA = 100 * 1024 * 1024;
-
- private Dialog dialog;
- private WebView inAppWebView;
- private EditText edittext;
- private boolean showLocationBar = true;
- private CallbackContext callbackContext;
- private String buttonLabel = "Done";
-
- /**
- * 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 boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- try {
- if (action.equals("open")) {
- this.callbackContext = callbackContext;
- String url = args.getString(0);
- String target = args.optString(1);
- if (target == null || target.equals("") || target.equals(NULL)) {
- target = SELF;
- }
- HashMap features = parseFeature(args.optString(2));
-
- Log.d(LOG_TAG, "target = " + target);
-
- url = updateUrl(url);
- String result = "";
-
- // SELF
- if (SELF.equals(target)) {
- Log.d(LOG_TAG, "in self");
- // load in webview
- if (url.startsWith("file://") || url.startsWith("javascript:")
- || Config.isUrlWhiteListed(url)) {
- this.webView.loadUrl(url);
- }
- //Load the dialer
- else if (url.startsWith(WebView.SCHEME_TEL))
- {
- try {
- Intent intent = new Intent(Intent.ACTION_DIAL);
- intent.setData(Uri.parse(url));
- this.cordova.getActivity().startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
- }
- }
- // load in InAppBrowser
- else {
- result = this.showWebPage(url, features);
- }
- }
- // SYSTEM
- else if (SYSTEM.equals(target)) {
- Log.d(LOG_TAG, "in system");
- result = this.openExternal(url);
- }
- // BLANK - or anything else
- else {
- Log.d(LOG_TAG, "in blank");
- result = this.showWebPage(url, features);
- }
-
- PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
- pluginResult.setKeepCallback(true);
- this.callbackContext.sendPluginResult(pluginResult);
- }
- else if (action.equals("close")) {
- closeDialog();
- this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
- }
- else if (action.equals("injectScriptCode")) {
- String jsWrapper = null;
- if (args.getBoolean(1)) {
- jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
- }
- injectDeferredObject(args.getString(0), jsWrapper);
- }
- else if (action.equals("injectScriptFile")) {
- String jsWrapper;
- if (args.getBoolean(1)) {
- jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
- } else {
- jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
- }
- injectDeferredObject(args.getString(0), jsWrapper);
- }
- else if (action.equals("injectStyleCode")) {
- String jsWrapper;
- if (args.getBoolean(1)) {
- jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
- } else {
- jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
- }
- injectDeferredObject(args.getString(0), jsWrapper);
- }
- else if (action.equals("injectStyleFile")) {
- String jsWrapper;
- if (args.getBoolean(1)) {
- jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
- } else {
- jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
- }
- injectDeferredObject(args.getString(0), jsWrapper);
- }
- else {
- return false;
- }
- } catch (JSONException e) {
- this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
- }
- return true;
- }
-
- /**
- * Inject an object (script or style) into the InAppBrowser WebView.
- *
- * This is a helper method for the inject{Script|Style}{Code|File} API calls, which
- * provides a consistent method for injecting JavaScript code into the document.
- *
- * If a wrapper string is supplied, then the source string will be JSON-encoded (adding
- * quotes) and wrapped using string formatting. (The wrapper string should have a single
- * '%s' marker)
- *
- * @param source The source object (filename or script/style text) to inject into
- * the document.
- * @param jsWrapper A JavaScript string to wrap the source string in, so that the object
- * is properly injected, or null if the source string is JavaScript text
- * which should be executed directly.
- */
- private void injectDeferredObject(String source, String jsWrapper) {
- String scriptToInject;
- if (jsWrapper != null) {
- org.json.JSONArray jsonEsc = new org.json.JSONArray();
- jsonEsc.put(source);
- String jsonRepr = jsonEsc.toString();
- String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
- scriptToInject = String.format(jsWrapper, jsonSourceString);
- } else {
- scriptToInject = source;
- }
- // This action will have the side-effect of blurring the currently focused element
- this.inAppWebView.loadUrl("javascript:" + scriptToInject);
- }
-
- /**
- * Put the list of features into a hash map
- *
- * @param optString
- * @return
- */
- private HashMap parseFeature(String optString) {
- if (optString.equals(NULL)) {
- return null;
- } else {
- HashMap map = new HashMap();
- StringTokenizer features = new StringTokenizer(optString, ",");
- StringTokenizer option;
- while(features.hasMoreElements()) {
- option = new StringTokenizer(features.nextToken(), "=");
- if (option.hasMoreElements()) {
- String key = option.nextToken();
- if (key.equalsIgnoreCase(CLOSE_BUTTON_CAPTION)) {
- this.buttonLabel = option.nextToken();
- } else {
- Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE;
- map.put(key, value);
- }
- }
- }
- return map;
- }
- }
-
- /**
- * Convert relative URL to full path
- *
- * @param url
- * @return
- */
- private String updateUrl(String url) {
- Uri newUrl = Uri.parse(url);
- if (newUrl.isRelative()) {
- url = this.webView.getUrl().substring(0, this.webView.getUrl().lastIndexOf("/")+1) + url;
- }
- return url;
- }
-
- /**
- * Display a new browser with the specified URL.
- *
- * @param url The url to load.
- * @param usePhoneGap Load url in PhoneGap webview
- * @return "" if ok, or error message.
- */
- public String openExternal(String url) {
- try {
- Intent intent = null;
- intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- this.cordova.getActivity().startActivity(intent);
- return "";
- } catch (android.content.ActivityNotFoundException e) {
- Log.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString());
- return e.toString();
- }
- }
-
- /**
- * Closes the dialog
- */
- private void closeDialog() {
- try {
- this.inAppWebView.loadUrl("about:blank");
- JSONObject obj = new JSONObject();
- obj.put("type", EXIT_EVENT);
-
- sendUpdate(obj, false);
- } catch (JSONException ex) {
- Log.d(LOG_TAG, "Should never happen");
- }
-
- if (dialog != null) {
- dialog.dismiss();
- }
- }
-
- /**
- * Checks to see if it is possible to go back one page in history, then does so.
- */
- private void goBack() {
- if (this.inAppWebView.canGoBack()) {
- this.inAppWebView.goBack();
- }
- }
-
- /**
- * Checks to see if it is possible to go forward one page in history, then does so.
- */
- private void goForward() {
- if (this.inAppWebView.canGoForward()) {
- this.inAppWebView.goForward();
- }
- }
-
- /**
- * Navigate to the new page
- *
- * @param url to load
- */
- private void navigate(String url) {
- InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
-
- if (!url.startsWith("http") && !url.startsWith("file:")) {
- this.inAppWebView.loadUrl("http://" + url);
- } else {
- this.inAppWebView.loadUrl(url);
- }
- this.inAppWebView.requestFocus();
- }
-
-
- /**
- * Should we show the location bar?
- *
- * @return boolean
- */
- private boolean getShowLocationBar() {
- return this.showLocationBar;
- }
-
- /**
- * Display a new browser with the specified URL.
- *
- * @param url The url to load.
- * @param jsonObject
- */
- public String showWebPage(final String url, HashMap features) {
- // Determine if we should hide the location bar.
- showLocationBar = true;
- if (features != null) {
- Boolean show = features.get(LOCATION);
- if (show != null) {
- showLocationBar = show.booleanValue();
- }
- }
-
- final CordovaWebView thatWebView = this.webView;
-
- // Create dialog in new thread
- Runnable runnable = new Runnable() {
- /**
- * Convert our DIP units to Pixels
- *
- * @return int
- */
- private int dpToPixels(int dipValue) {
- int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,
- (float) dipValue,
- cordova.getActivity().getResources().getDisplayMetrics()
- );
-
- return value;
- }
-
- public void run() {
- // Let's create the main dialog
- dialog = new Dialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar);
- dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog;
- dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
- dialog.setCancelable(true);
- dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
- public void onDismiss(DialogInterface dialog) {
- try {
- JSONObject obj = new JSONObject();
- obj.put("type", EXIT_EVENT);
-
- sendUpdate(obj, false);
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Should never happen");
- }
- }
- });
-
- // Main container layout
- LinearLayout main = new LinearLayout(cordova.getActivity());
- main.setOrientation(LinearLayout.VERTICAL);
-
- // Toolbar layout
- RelativeLayout toolbar = new RelativeLayout(cordova.getActivity());
- toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44)));
- toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2));
- toolbar.setHorizontalGravity(Gravity.LEFT);
- toolbar.setVerticalGravity(Gravity.TOP);
-
- // Action Button Container layout
- RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity());
- actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- actionButtonContainer.setHorizontalGravity(Gravity.LEFT);
- actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);
- actionButtonContainer.setId(1);
-
- // Back button
- Button back = new Button(cordova.getActivity());
- RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
- backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT);
- back.setLayoutParams(backLayoutParams);
- back.setContentDescription("Back Button");
- back.setId(2);
- back.setText("<");
- back.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- goBack();
- }
- });
-
- // Forward button
- Button forward = new Button(cordova.getActivity());
- RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
- forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2);
- forward.setLayoutParams(forwardLayoutParams);
- forward.setContentDescription("Forward Button");
- forward.setId(3);
- forward.setText(">");
- forward.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- goForward();
- }
- });
-
- // Edit Text Box
- edittext = new EditText(cordova.getActivity());
- RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
- textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
- edittext.setLayoutParams(textLayoutParams);
- edittext.setId(4);
- edittext.setSingleLine(true);
- edittext.setText(url);
- edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
- edittext.setImeOptions(EditorInfo.IME_ACTION_GO);
- edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE
- edittext.setOnKeyListener(new View.OnKeyListener() {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // If the event is a key-down event on the "enter" button
- if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
- navigate(edittext.getText().toString());
- return true;
- }
- return false;
- }
- });
-
- // Close button
- Button close = new Button(cordova.getActivity());
- RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
- closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
- close.setLayoutParams(closeLayoutParams);
- forward.setContentDescription("Close Button");
- close.setId(5);
- close.setText(buttonLabel);
- close.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- closeDialog();
- }
- });
-
- // WebView
- inAppWebView = new WebView(cordova.getActivity());
- inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView));
- WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
- inAppWebView.setWebViewClient(client);
- WebSettings settings = inAppWebView.getSettings();
- settings.setJavaScriptEnabled(true);
- settings.setJavaScriptCanOpenWindowsAutomatically(true);
- settings.setBuiltInZoomControls(true);
- /**
- * We need to be careful of this line as a future Android release may deprecate it out of existence.
- * Can't replace it with the API 8 level call right now as our minimum SDK is 7 until May 2013
- */
- // @TODO: replace with settings.setPluginState(android.webkit.WebSettings.PluginState.ON)
- settings.setPluginsEnabled(true);
-
- //Toggle whether this is enabled or not!
- Bundle appSettings = cordova.getActivity().getIntent().getExtras();
- boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true);
- if(enableDatabase)
- {
- String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
- settings.setDatabasePath(databasePath);
- settings.setDatabaseEnabled(true);
- }
- settings.setDomStorageEnabled(true);
-
- inAppWebView.loadUrl(url);
- inAppWebView.setId(6);
- inAppWebView.getSettings().setLoadWithOverviewMode(true);
- inAppWebView.getSettings().setUseWideViewPort(true);
- inAppWebView.requestFocus();
- inAppWebView.requestFocusFromTouch();
-
- // Add the back and forward buttons to our action button container layout
- actionButtonContainer.addView(back);
- actionButtonContainer.addView(forward);
-
- // Add the views to our toolbar
- toolbar.addView(actionButtonContainer);
- toolbar.addView(edittext);
- toolbar.addView(close);
-
- // Don't add the toolbar if its been disabled
- if (getShowLocationBar()) {
- // Add our toolbar to our main view/layout
- main.addView(toolbar);
- }
-
- // Add our webview to our main view/layout
- main.addView(inAppWebView);
-
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
- lp.copyFrom(dialog.getWindow().getAttributes());
- lp.width = WindowManager.LayoutParams.MATCH_PARENT;
- lp.height = WindowManager.LayoutParams.MATCH_PARENT;
-
- dialog.setContentView(main);
- dialog.show();
- dialog.getWindow().setAttributes(lp);
- }
- };
- this.cordova.getActivity().runOnUiThread(runnable);
- return "";
- }
-
- /**
- * Create a new plugin success result and send it back to JavaScript
- *
- * @param obj a JSONObject contain event payload information
- */
- private void sendUpdate(JSONObject obj, boolean keepCallback) {
- sendUpdate(obj, keepCallback, PluginResult.Status.OK);
- }
-
- /**
- * Create a new plugin result and send it back to JavaScript
- *
- * @param obj a JSONObject contain event payload information
- * @param status the status code to return to the JavaScript environment
- */ private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
- PluginResult result = new PluginResult(status, obj);
- result.setKeepCallback(keepCallback);
- this.callbackContext.sendPluginResult(result);
- }
-
- public class InAppChromeClient extends WebChromeClient {
-
- private CordovaWebView webView;
-
- public InAppChromeClient(CordovaWebView webView) {
- super();
- this.webView = webView;
- }
- /**
- * 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(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
-
- if (estimatedSize < MAX_QUOTA)
- {
- //increase for 1Mb
- long newQuota = estimatedSize;
- LOG.d(LOG_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);
- }
- }
-
- /**
- * 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
- */
- @Override
- public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
- super.onGeolocationPermissionsShowPrompt(origin, callback);
- callback.invoke(origin, true, false);
- }
-
- /**
- * 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.
- *
- * The prompt bridge provided for the InAppBrowser is capable of executing any
- * oustanding callback belonging to the InAppBrowser plugin. Care has been
- * taken that other callbacks cannot be triggered, and that no other code
- * execution is possible.
- *
- * To trigger the bridge, the prompt default value should be of the form:
- *
- * gap-iab://
- *
- * where is the string id of the callback to trigger (something
- * like "InAppBrowser0123456789")
- *
- * If present, the prompt message is expected to be a JSON-encoded value to
- * pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid.
- *
- * @param view
- * @param url
- * @param message
- * @param defaultValue
- * @param result
- */
- @Override
- public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
- // See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute.
- if (defaultValue != null && defaultValue.startsWith("gap-iab://")) {
- PluginResult scriptResult;
- String scriptCallbackId = defaultValue.substring(10);
- if (scriptCallbackId.startsWith("InAppBrowser")) {
- if(message == null || message.length() == 0) {
- scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray());
- } else {
- try {
- scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message));
- } catch(JSONException e) {
- scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
- }
- }
- this.webView.sendPluginResult(scriptResult, scriptCallbackId);
- result.confirm("");
- return true;
- }
- }
- return false;
- }
-
- }
-
- /**
- * The webview client receives notifications about appView
- */
- public class InAppBrowserClient extends WebViewClient {
- EditText edittext;
- CordovaWebView webView;
-
- /**
- * Constructor.
- *
- * @param mContext
- * @param edittext
- */
- public InAppBrowserClient(CordovaWebView webView, EditText mEditText) {
- this.webView = webView;
- this.edittext = mEditText;
- }
-
- /**
- * Notify the host application that a page has started loading.
- *
- * @param view The webview initiating the callback.
- * @param url The url of the page.
- */
- @Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- super.onPageStarted(view, url, favicon);
- String newloc = "";
- if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
- newloc = 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));
- cordova.getActivity().startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
- }
- }
-
- else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:")) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- cordova.getActivity().startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- LOG.e(LOG_TAG, "Error with " + 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");
- cordova.getActivity().startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
- }
- }
- else {
- newloc = "http://" + url;
- }
-
- if (!newloc.equals(edittext.getText().toString())) {
- edittext.setText(newloc);
- }
-
- try {
- JSONObject obj = new JSONObject();
- obj.put("type", LOAD_START_EVENT);
- obj.put("url", newloc);
-
- sendUpdate(obj, true);
- } catch (JSONException ex) {
- Log.d(LOG_TAG, "Should never happen");
- }
- }
-
- public void onPageFinished(WebView view, String url) {
- super.onPageFinished(view, url);
-
- try {
- JSONObject obj = new JSONObject();
- obj.put("type", LOAD_STOP_EVENT);
- obj.put("url", url);
-
- sendUpdate(obj, true);
- } catch (JSONException ex) {
- Log.d(LOG_TAG, "Should never happen");
- }
- }
-
- public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
- super.onReceivedError(view, errorCode, description, failingUrl);
-
- try {
- JSONObject obj = new JSONObject();
- obj.put("type", LOAD_ERROR_EVENT);
- obj.put("url", failingUrl);
- obj.put("code", errorCode);
- obj.put("message", description);
-
- sendUpdate(obj, true, PluginResult.Status.ERROR);
- } catch (JSONException ex) {
- Log.d(LOG_TAG, "Should never happen");
- }
-
- }
- }
-}
diff --git a/framework/src/org/apache/cordova/NetworkListener.java b/framework/src/org/apache/cordova/NetworkListener.java
deleted file mode 100755
index 7d192595..00000000
--- a/framework/src/org/apache/cordova/NetworkListener.java
+++ /dev/null
@@ -1,32 +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 org.apache.cordova;
-
-import android.location.LocationManager;
-
-/**
- * This class handles requests for GPS location services.
- *
- */
-public class NetworkListener extends CordovaLocationListener {
- public NetworkListener(LocationManager locationManager, GeoBroker m) {
- super(locationManager, m, "[Cordova NetworkListener]");
- }
-}
diff --git a/framework/src/org/apache/cordova/NetworkManager.java b/framework/src/org/apache/cordova/NetworkManager.java
deleted file mode 100755
index bb4743f2..00000000
--- a/framework/src/org/apache/cordova/NetworkManager.java
+++ /dev/null
@@ -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 org.apache.cordova;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-
-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 CordovaPlugin {
-
- 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 type
- 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 CallbackContext connectionCallbackContext;
- private boolean registered = false;
-
- ConnectivityManager sockMan;
- BroadcastReceiver receiver;
- private String lastStatus = "";
-
- /**
- * 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 cordova The context of the main Activity.
- * @param webView The CordovaWebView Cordova is running in.
- */
- public void initialize(CordovaInterface cordova, CordovaWebView webView) {
- super.initialize(cordova, webView);
- this.sockMan = (ConnectivityManager) cordova.getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
- this.connectionCallbackContext = 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) {
- // (The null check is for the ARM Emulator, please use Intel Emulator for better results)
- if(NetworkManager.this.webView != null)
- updateConnectionInfo(sockMan.getActiveNetworkInfo());
- }
- };
- cordova.getActivity().registerReceiver(this.receiver, intentFilter);
- this.registered = true;
- }
-
- }
-
- /**
- * Executes the request and returns PluginResult.
- *
- * @param action The action to execute.
- * @param args JSONArry of arguments for the plugin.
- * @param callbackContext The callback id used when calling back into JavaScript.
- * @return True if the action was valid, false otherwise.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
- if (action.equals("getConnectionInfo")) {
- this.connectionCallbackContext = callbackContext;
- NetworkInfo info = sockMan.getActiveNetworkInfo();
- PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, this.getConnectionInfo(info));
- pluginResult.setKeepCallback(true);
- callbackContext.sendPluginResult(pluginResult);
- return true;
- }
- return false;
- }
-
- /**
- * Stop network receiver.
- */
- public void onDestroy() {
- if (this.receiver != null && this.registered) {
- try {
- this.cordova.getActivity().unregisterReceiver(this.receiver);
- this.registered = false;
- } 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"
- // Jellybean sends its own info
- String thisStatus = this.getConnectionInfo(info);
- if(!thisStatus.equals(lastStatus))
- {
- sendUpdate(thisStatus);
- lastStatus = thisStatus;
- }
-
- }
-
- /**
- * 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);
- }
- }
- Log.d("CordovaNetworkManager", "Connection Type: " + type);
- 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) {
- if (connectionCallbackContext != null) {
- PluginResult result = new PluginResult(PluginResult.Status.OK, type);
- result.setKeepCallback(true);
- connectionCallbackContext.sendPluginResult(result);
- }
- webView.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;
- }
-}
diff --git a/framework/src/org/apache/cordova/Notification.java b/framework/src/org/apache/cordova/Notification.java
deleted file mode 100755
index cf2e95f8..00000000
--- a/framework/src/org/apache/cordova/Notification.java
+++ /dev/null
@@ -1,448 +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 org.apache.cordova;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-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;
-import android.widget.EditText;
-
-/**
- * This class provides access to notifications on the device.
- */
-public class Notification extends CordovaPlugin {
-
- 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 JSONArray of arguments for the plugin.
- * @param callbackContext The callback context used when calling back into JavaScript.
- * @return True when the action was valid, false otherwise.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- 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), callbackContext);
- return true;
- }
- else if (action.equals("confirm")) {
- this.confirm(args.getString(0), args.getString(1), args.getJSONArray(2), callbackContext);
- return true;
- }
- else if (action.equals("prompt")) {
- this.prompt(args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), callbackContext);
- return true;
- }
- 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();
- }
- else {
- return false;
- }
-
- // Only alert and confirm are async.
- callbackContext.success();
- return true;
- }
-
- //--------------------------------------------------------------------------
- // 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.cordova.getActivity().getBaseContext(), 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.cordova.getActivity().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 callbackContext The callback context
- */
- public synchronized void alert(final String message, final String title, final String buttonLabel, final CallbackContext callbackContext) {
-
- final CordovaInterface cordova = this.cordova;
-
- Runnable runnable = new Runnable() {
- public void run() {
-
- AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
- dlg.setMessage(message);
- dlg.setTitle(title);
- dlg.setCancelable(true);
- dlg.setPositiveButton(buttonLabel,
- new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
- }
- });
- dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
- public void onCancel(DialogInterface dialog)
- {
- dialog.dismiss();
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
- }
- });
-
- dlg.create();
- dlg.show();
- };
- };
- this.cordova.getActivity().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 callbackContext The callback context.
- */
- public synchronized void confirm(final String message, final String title, final JSONArray buttonLabels, final CallbackContext callbackContext) {
-
- final CordovaInterface cordova = this.cordova;
-
- Runnable runnable = new Runnable() {
- public void run() {
- AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
- dlg.setMessage(message);
- dlg.setTitle(title);
- dlg.setCancelable(true);
-
- // First button
- if (buttonLabels.length() > 0) {
- try {
- dlg.setNegativeButton(buttonLabels.getString(0),
- new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 1));
- }
- });
- } catch (JSONException e) { }
- }
-
- // Second button
- if (buttonLabels.length() > 1) {
- try {
- dlg.setNeutralButton(buttonLabels.getString(1),
- new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 2));
- }
- });
- } catch (JSONException e) { }
- }
-
- // Third button
- if (buttonLabels.length() > 2) {
- try {
- dlg.setPositiveButton(buttonLabels.getString(2),
- new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 3));
- }
- });
- } catch (JSONException e) { }
- }
- dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
- public void onCancel(DialogInterface dialog)
- {
- dialog.dismiss();
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
- }
- });
-
- dlg.create();
- dlg.show();
- };
- };
- this.cordova.getActivity().runOnUiThread(runnable);
- }
-
- /**
- * Builds and shows a native Android prompt dialog with given title, message, buttons.
- * This dialog only shows up to 3 buttons. Any labels after that will be ignored.
- * The following results are returned to the JavaScript callback identified by callbackId:
- * buttonIndex Index number of the button selected
- * input1 The text entered in the prompt dialog box
- *
- * @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 callbackContext The callback context.
- */
- public synchronized void prompt(final String message, final String title, final JSONArray buttonLabels, final String defaultText, final CallbackContext callbackContext) {
-
- final CordovaInterface cordova = this.cordova;
- final EditText promptInput = new EditText(cordova.getActivity());
- promptInput.setHint(defaultText);
-
- Runnable runnable = new Runnable() {
- public void run() {
- AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
- dlg.setMessage(message);
- dlg.setTitle(title);
- dlg.setCancelable(true);
-
- dlg.setView(promptInput);
-
- final JSONObject result = new JSONObject();
-
- // First button
- if (buttonLabels.length() > 0) {
- try {
- dlg.setNegativeButton(buttonLabels.getString(0),
- new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- try {
- result.put("buttonIndex",1);
- result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText());
- } catch (JSONException e) { e.printStackTrace(); }
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
- }
- });
- } catch (JSONException e) { }
- }
-
- // Second button
- if (buttonLabels.length() > 1) {
- try {
- dlg.setNeutralButton(buttonLabels.getString(1),
- new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- try {
- result.put("buttonIndex",2);
- result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText());
- } catch (JSONException e) { e.printStackTrace(); }
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
- }
- });
- } catch (JSONException e) { }
- }
-
- // Third button
- if (buttonLabels.length() > 2) {
- try {
- dlg.setPositiveButton(buttonLabels.getString(2),
- new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- try {
- result.put("buttonIndex",3);
- result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText());
- } catch (JSONException e) { e.printStackTrace(); }
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
- }
- });
- } catch (JSONException e) { }
- }
- dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
- public void onCancel(DialogInterface dialog){
- dialog.dismiss();
- try {
- result.put("buttonIndex",0);
- result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText());
- } catch (JSONException e) { e.printStackTrace(); }
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
- }
- });
-
- dlg.create();
- dlg.show();
-
- };
- };
- this.cordova.getActivity().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 CordovaInterface cordova = this.cordova;
- Runnable runnable = new Runnable() {
- public void run() {
- Notification.this.spinnerDialog = ProgressDialog.show(cordova.getActivity(), title, message, true, true,
- new DialogInterface.OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- Notification.this.spinnerDialog = null;
- }
- });
- }
- };
- this.cordova.getActivity().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 CordovaInterface cordova = this.cordova;
- Runnable runnable = new Runnable() {
- public void run() {
- notification.progressDialog = new ProgressDialog(cordova.getActivity());
- 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.cordova.getActivity().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;
- }
- }
-}
diff --git a/framework/src/org/apache/cordova/SplashScreen.java b/framework/src/org/apache/cordova/SplashScreen.java
deleted file mode 100644
index 66b5baeb..00000000
--- a/framework/src/org/apache/cordova/SplashScreen.java
+++ /dev/null
@@ -1,43 +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 org.apache.cordova;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.json.JSONArray;
-
-public class SplashScreen extends CordovaPlugin {
-
- @Override
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
- if (action.equals("hide")) {
- this.webView.postMessage("splashscreen", "hide");
- } else if (action.equals("show")){
- this.webView.postMessage("splashscreen", "show");
- }
- else {
- return false;
- }
-
- callbackContext.success();
- return true;
- }
-
-}
diff --git a/framework/src/org/apache/cordova/Storage.java b/framework/src/org/apache/cordova/Storage.java
deleted file mode 100755
index 34ebf387..00000000
--- a/framework/src/org/apache/cordova/Storage.java
+++ /dev/null
@@ -1,244 +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 org.apache.cordova;
-
-import java.io.File;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-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 CordovaPlugin {
-
- // 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 callbackContext
- * The callback context used when calling back into JavaScript.
- * @return True if the action was valid, false otherwise.
- */
- public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- 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));
- }
- else {
- return false;
- }
- callbackContext.success();
- return true;
- }
-
- /**
- * Clean up and close database.
- */
- @Override
- public void onDestroy() {
- if (this.myDb != null) {
- this.myDb.close();
- this.myDb = null;
- }
- }
-
- /**
- * Clean up on navigation/refresh.
- */
- public void onReset() {
- this.onDestroy();
- }
-
- // --------------------------------------------------------------------------
- // 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.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
- }
-
- this.dbName = this.path + File.separator + db + ".db";
-
- /*
- * What is all this nonsense? Well the separator was incorrect so the db was showing up in the wrong
- * directory. This bit of code fixes that issue and moves the db to the correct directory.
- */
- File oldDbFile = new File(this.path + File.pathSeparator + db + ".db");
- if (oldDbFile.exists()) {
- File dbPath = new File(this.path);
- File dbFile = new File(dbName);
- dbPath.mkdirs();
- oldDbFile.renameTo(dbFile);
- }
-
- 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.webView.sendJavascript("cordova.require('cordova/plugin/android/storage').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.webView.sendJavascript("cordova.require('cordova/plugin/android/storage').failQuery('" + ex.getMessage() + "','" + tx_id + "');");
- }
- }
-
- /**
- * Checks to see the the query is a Data Definition 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.webView.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', " + result + ");");
- }
-
-}