--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="de.android.mobiads"
+ android:versionCode="1"
+ android:versionName="1.0" android:installLocation="internalOnly">
+
+ <uses-sdk android:minSdkVersion="15" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <application
+ android:icon="@drawable/ic_launcher" android:label="@string/app_name"
+ android:description="@string/app_description" android:hardwareAccelerated="false"
+ android:largeHeap="false" android:testOnly="false">
+ <activity
+ android:label="@string/app_name"
+ android:name=".MobiAdsLoginActivity"
+ android:screenOrientation="portrait"
+ android:configChanges="touchscreen|keyboard"
+ android:theme="@android:style/Theme.Black"
+ android:launchMode="standard"
+ android:noHistory="true"
+ android:description="@string/app_description">
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:label="@string/app_name"
+ android:name=".MobiAdsMainActivity"
+ android:theme="@android:style/Theme.Black"
+ android:screenOrientation="portrait"
+ android:configChanges="touchscreen|keyboard">
+ <intent-filter>
+ <action android:name="android.intent.action.MOBIADS"/>
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <service
+ android:name=".MobiAdsService"
+ android:process=":mobiadsservice" >
+ </service>
+
+ <provider
+ android:authorities="de.android.mobiads.provider"
+ android:enabled="true"
+ android:exported="false"
+ android:grantUriPermissions="false"
+ android:icon="@drawable/ic_launcher"
+ android:initOrder="1"
+ android:label="@string/app_name"
+ android:multiprocess="false"
+ android:name=".provider.IndexerProvider"
+ android:permission="android.permission.MOBIADS"
+ android:readPermission="android.permission.READ_MOBIADS"
+ android:syncable="false"
+ android:writePermission="android.permission.WRITE_MOBIADS" >
+ <grant-uri-permission android:pathPattern=".*" />
+ </provider>
+ <!--
+ <provider
+ android:process="string" When having my service, here I should write the service process name
+ </provider>-->
+
+ </application>
+
+
+
+</manifest>
\ No newline at end of file
--- /dev/null
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package de.android.mobiads;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class drawable {
+ public static final int alert_dialog_icon=0x7f020000;
+ public static final int ic_launcher=0x7f020001;
+ }
+ public static final class id {
+ public static final int cancel_button=0x7f050005;
+ public static final int frameLayout1=0x7f050000;
+ public static final int frameLayout2=0x7f050003;
+ public static final int login_button=0x7f050004;
+ public static final int password=0x7f050002;
+ public static final int username=0x7f050001;
+ }
+ public static final class layout {
+ public static final int main=0x7f030000;
+ public static final int mobiadsmain=0x7f030001;
+ }
+ public static final class string {
+ public static final int alert_dialog_cancel=0x7f040003;
+ public static final int app_description=0x7f040002;
+ public static final int app_name=0x7f040001;
+ public static final int button_cancel=0x7f04000e;
+ public static final int button_login=0x7f040008;
+ public static final int button_messagebind=0x7f040009;
+ public static final int button_messagestartservice=0x7f04000c;
+ public static final int button_messagestopservice=0x7f04000b;
+ public static final int button_messageunbind=0x7f04000a;
+ public static final int button_ok=0x7f04000d;
+ public static final int encoded_web_service=0x7f040014;
+ public static final int error_dialog_connection_error=0x7f040004;
+ public static final int error_dialog_userpwd_error=0x7f040005;
+ public static final int hello=0x7f040000;
+ public static final int password=0x7f040007;
+ public static final int remote_service_label=0x7f040011;
+ public static final int remote_service_started=0x7f04000f;
+ public static final int remote_service_stopped=0x7f040010;
+ public static final int url_login_web_service=0x7f040012;
+ public static final int user_agent_web_service=0x7f040013;
+ public static final int username=0x7f040006;
+ }
+}
--- /dev/null
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
--- /dev/null
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-15
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:gravity="right"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:weightSum="1">
+
+ <FrameLayout
+ android:id="@+id/frameLayout1"
+ android:layout_width="match_parent"
+ android:layout_height="70dp">
+ </FrameLayout>
+
+ <EditText
+ android:id="@+id/username"
+ android:singleLine="true"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/username"/>
+
+ <EditText
+ android:id="@+id/password"
+ android:password="true"
+ android:singleLine="true"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/password"/>
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:id="@+id/frameLayout2"
+ android:layout_height="30dp">
+ </FrameLayout>
+ <Button
+ android:id="@+id/login_button"
+ android:onClick="onClickLogin"
+ android:layout_height="wrap_content"
+ android:text="@string/button_login"
+ android:layout_width="match_parent"
+ android:layout_gravity="center"/>
+ <Button
+ android:id="@+id/cancel_button"
+ android:onClick="onClickCancel"
+ android:gravity="right"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="right"
+ android:text="@string/button_cancel"/>
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="right"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/hello" />
+ <FrameLayout
+ android:id="@+id/frameLayout1"
+ android:layout_width="match_parent"
+ android:layout_height="30dp">
+ </FrameLayout>
+ <Button
+ android:id="@+id/login_button"
+ android:onClick="onClickBind"
+ android:layout_height="wrap_content"
+ android:text="@string/button_messagebind"
+ android:layout_width="match_parent"
+ android:layout_gravity="center"/>
+ <FrameLayout
+ android:id="@+id/frameLayout1"
+ android:layout_width="match_parent"
+ android:layout_height="30dp">
+ </FrameLayout>
+ <Button
+ android:id="@+id/login_button"
+ android:onClick="onClickUnBind"
+ android:layout_height="wrap_content"
+ android:text="@string/button_messageunbind"
+ android:layout_width="match_parent"
+ android:layout_gravity="center"/>
+ <FrameLayout
+ android:id="@+id/frameLayout1"
+ android:layout_width="match_parent"
+ android:layout_height="30dp">
+ </FrameLayout>
+ <Button
+ android:id="@+id/login_button"
+ android:onClick="onClickStopService"
+ android:layout_height="wrap_content"
+ android:text="@string/button_messagestopservice"
+ android:layout_width="match_parent"
+ android:layout_gravity="center"/>
+ <FrameLayout
+ android:id="@+id/frameLayout1"
+ android:layout_width="match_parent"
+ android:layout_height="30dp">
+ </FrameLayout>
+ <Button
+ android:id="@+id/login_button"
+ android:onClick="onClickStartService"
+ android:layout_height="wrap_content"
+ android:text="@string/button_messagestartservice"
+ android:layout_width="match_parent"
+ android:layout_gravity="center"/>
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="hello">Hello World, MobiAdsActivity!</string>
+ <string name="app_name">MobiAds</string>
+ <string name="app_description">Receive notifications about offers and discounts.</string>
+ <string name="alert_dialog_cancel">Do you really want to close the application?</string>
+ <string name="error_dialog_connection_error">Connection error with MobiAd server.</string>
+ <string name="error_dialog_userpwd_error">The username or password you entered is incorrect.</string>
+ <string name="username">Username</string>
+ <string name="password">Password</string>
+ <string name="button_login">Log In</string>
+ <string name="button_messagebind">Bind Service</string>
+ <string name="button_messageunbind">Unbind Service</string>
+ <string name="button_messagestopservice">Stop Application</string>
+ <string name="button_messagestartservice">Start Application</string>
+ <string name="button_ok">OK</string>
+ <string name="button_cancel">Cancel</string>
+ <string name="remote_service_started">MobiAds Service Started</string>
+ <string name="remote_service_stopped">MobiAds Service Stopped</string>
+ <string name="remote_service_label">MobiAds Service</string>
+ <string name="url_login_web_service">http://users.mobiads.gumartinm.name/userfront.php/api/login/auth.json</string>
+ <string name="user_agent_web_service">MobieAds/1.0</string>
+ <string name="encoded_web_service">UTF-8</string>
+
+</resources>
\ No newline at end of file
--- /dev/null
+package de.android.mobiads;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.params.CoreProtocolPNames;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.ComponentName;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.StrictMode;
+import android.util.Log;
+import android.view.View;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+import android.widget.EditText;
+
+public class MobiAdsLoginActivity extends Activity {
+ private static final String TAG = "MobiAdsLoginActivity";
+ private static final String SETCOOKIEFIELD = "Set-Cookie";
+ private StrictMode.ThreadPolicy currentPolicy;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ CookieSyncManager.createInstance(this);
+ currentPolicy = StrictMode.getThreadPolicy();
+ StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX);
+ setContentView(R.layout.main);
+ }
+
+ public void onClickLogin(View v) {
+ final EditText password = (EditText) findViewById(R.id.password);
+ final EditText username = (EditText) findViewById(R.id.username);
+ final HttpClient httpClient = new DefaultHttpClient();
+ String pruba = getResources().getString(R.string.url_login_web_service);
+ final HttpPost httpPost = new HttpPost(pruba);
+ HttpEntity httpEntity = null;
+ HttpResponse httpResponse = null;
+ final List<NameValuePair> formParams = new ArrayList<NameValuePair>(2);
+
+ httpClient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, getResources().getString(R.string.encoded_web_service));
+ httpClient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, getResources().getString(R.string.user_agent_web_service));
+ httpClient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
+ //TODO: RESTful Web Service must use JSON instead of signin array :(
+ formParams.add(new BasicNameValuePair("signin[username]", username.getText().toString()));
+ formParams.add(new BasicNameValuePair("signin[password]", password.getText().toString()));
+ try {
+ httpEntity = new UrlEncodedFormEntity(formParams, getResources().getString(R.string.encoded_web_service));
+ httpPost.setEntity(httpEntity);
+ httpResponse = httpClient.execute(httpPost);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(TAG, "Error while encoding POST parameters.", e);
+ } catch (ClientProtocolException e) {
+ Log.e(TAG, "Error while executing HTTP client connection.", e);
+ createErrorDialog(R.string.error_dialog_connection_error);
+ } catch (IOException e) {
+ Log.e(TAG, "Error while executing HTTP client connection.", e);
+ createErrorDialog(R.string.error_dialog_connection_error);
+ } finally {
+ httpClient.getConnectionManager().shutdown();
+ }
+
+ if (httpResponse != null) {
+ switch (httpResponse.getStatusLine().getStatusCode()) {
+ case HttpStatus.SC_OK:
+ String cookie = httpResponse.getLastHeader(SETCOOKIEFIELD).getValue();
+ if (cookie != null) {
+ CookieManager.getInstance().setCookie("users.mobiads.gumartinm.name",cookie);
+ CookieSyncManager.getInstance().sync();
+ //Go to the next activity
+ StrictMode.setThreadPolicy(currentPolicy);
+ this.startActivity(new Intent("android.intent.action.MOBIADS").
+ setComponent(new ComponentName("de.android.mobiads", "de.android.mobiads.MobiAdsMainActivity")));
+ } else {
+ Log.e(TAG, "There must be a weird issue with the server because... There is not cookie!!!!");
+ createErrorDialog(R.string.error_dialog_connection_error);
+ }
+ break;
+ case HttpStatus.SC_UNAUTHORIZED:
+ //Username or password is incorrect
+ createErrorDialog(R.string.error_dialog_userpwd_error);
+ break;
+ case HttpStatus.SC_BAD_REQUEST:
+ //What the heck are you doing?
+ createErrorDialog(R.string.error_dialog_userpwd_error);
+ break;
+ default:
+ Log.e(TAG, "Error while retrieving the HTTP status line.");
+ createErrorDialog(R.string.error_dialog_connection_error);
+ break;
+ }
+ }
+ else {
+ Log.e(TAG, "No response? This should never have happened.");
+ createErrorDialog(R.string.error_dialog_connection_error);
+ }
+ }
+
+ public void onClickCancel(View v) {
+ createAlertDialog(R.string.alert_dialog_cancel);
+ }
+
+ void createAlertDialog(int title) {
+ DialogFragment newFragment = AlertDialogFragment.newInstance(title);
+ newFragment.show(getFragmentManager(), "alertDialog");
+ }
+
+ void createErrorDialog(int title) {
+ DialogFragment newFragment = ErrorDialogFragment.newInstance(title);
+ newFragment.show(getFragmentManager(), "errorDialog");
+ }
+
+ public void doPositiveClick() {
+ StrictMode.setThreadPolicy(currentPolicy);
+ finish();
+ }
+
+ public void doNegativeClick() {
+
+ }
+
+
+ public static class AlertDialogFragment extends DialogFragment {
+
+ public static AlertDialogFragment newInstance(int title) {
+ AlertDialogFragment frag = new AlertDialogFragment();
+ Bundle args = new Bundle();
+
+ args.putInt("title", title);
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ int title = getArguments().getInt("title");
+
+ return new AlertDialog.Builder(getActivity())
+ .setIcon(R.drawable.alert_dialog_icon)
+ .setTitle(title)
+ .setPositiveButton(R.string.button_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ ((MobiAdsLoginActivity)getActivity()).doPositiveClick();
+ }
+ }
+ )
+ .setNegativeButton(R.string.button_cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ ((MobiAdsLoginActivity)getActivity()).doNegativeClick();
+ }
+ }
+ )
+ .create();
+ }
+ }
+
+
+ public static class ErrorDialogFragment extends DialogFragment {
+
+ public static ErrorDialogFragment newInstance(int title) {
+ ErrorDialogFragment frag = new ErrorDialogFragment();
+ Bundle args = new Bundle();
+
+ args.putInt("title", title);
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ int title = getArguments().getInt("title");
+
+ return new AlertDialog.Builder(getActivity())
+ .setIcon(R.drawable.alert_dialog_icon)
+ .setTitle(title)
+ .setPositiveButton(R.string.button_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+
+ }
+ }
+ )
+ .create();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package de.android.mobiads;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class MobiAdsMainActivity extends Activity {
+ /** Messenger for communicating with service. */
+ Messenger mService = null;
+ /** Flag indicating whether we have called bind on the service. */
+ boolean mIsBound;
+ /** Some text view we are using to show state information. */
+ TextView mCallbackText;
+ /**
+ * Target we publish for clients to send messages to IncomingHandler.
+ */
+ final Messenger mMessenger = new Messenger(new IncomingHandler());
+ private static final String TAG = "MobiAdsMainActivity";
+
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.mobiadsmain);
+ }
+
+ /**
+ * Handler of incoming messages from service.
+ */
+ class IncomingHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MobiAdsService.MSG_SET_VALUE:
+ mCallbackText.setText("Received from service: " + msg.arg1);
+ break;
+ default:
+ super.handleMessage(msg);
+ }
+ }
+ }
+
+
+
+ /**
+ * Class for interacting with the main interface of the service.
+ */
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className,
+ IBinder service) {
+ // This is called when the connection with the service has been
+ // established, giving us the service object we can use to
+ // interact with the service. We are communicating with our
+ // service through an IDL interface, so get a client-side
+ // representation of that from the raw service object.
+ mService = new Messenger(service);
+ mCallbackText.setText("Attached.");
+
+ // We want to monitor the service for as long as we are
+ // connected to it.
+ try {
+ Message msg = Message.obtain(null,
+ MobiAdsService.MSG_REGISTER_CLIENT);
+ msg.replyTo = mMessenger;
+ mService.send(msg);
+
+ // Give it some value as an example.
+ msg = Message.obtain(null,
+ MobiAdsService.MSG_SET_VALUE, this.hashCode(), 0);
+ mService.send(msg);
+ } catch (RemoteException e) {
+ // In this case the service has crashed before we could even
+ // do anything with it; we can count on soon being
+ // disconnected (and then reconnected if it can be restarted)
+ // so there is no need to do anything here.
+ }
+
+ // As part of the sample, tell the user what happened.
+ Toast.makeText(MobiAdsMainActivity.this, R.string.remote_service_started,
+ Toast.LENGTH_SHORT).show();
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ // This is called when the connection with the service has been
+ // unexpectedly disconnected -- that is, its process crashed.
+ mService = null;
+ mCallbackText.setText("Disconnected.");
+
+ // As part of the sample, tell the user what happened.
+ Toast.makeText(MobiAdsMainActivity.this, R.string.remote_service_stopped,
+ Toast.LENGTH_SHORT).show();
+ }
+ };
+
+ void doBindService() {
+ // Establish a connection with the service. We use an explicit
+ // class name because there is no reason to be able to let other
+ // applications replace our component.
+ boolean prueba = bindService(new Intent(MobiAdsMainActivity.this,
+ MobiAdsService.class), mConnection, Context.BIND_AUTO_CREATE);
+ mIsBound = true;
+ mCallbackText.setText("Binding.");
+ }
+
+
+ public void onClickBind(View v) {
+ mCallbackText = new TextView(this);
+ this.doBindService();
+ }
+
+
+ public void onClickUnBind(View v) {
+ this.unbindService(mConnection);
+ }
+
+ public void onClickStopService(View v) {
+ this.stopService(new Intent(MobiAdsMainActivity.this, MobiAdsService.class));
+ }
+
+
+ public void onClickStartService(View v) {
+ this.startService(new Intent(MobiAdsMainActivity.this, MobiAdsService.class));
+ }
+}
--- /dev/null
+package de.android.mobiads;
+
+import de.android.mobiads.batch.MobiAdsBatch;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.IBinder;
+
+public class MobiAdsService extends Service {
+ private MobiAdsBatch mobiAdsBatch;
+ /** For showing and hiding our notification. */
+ NotificationManager notificationManager;
+ /**
+ * Command to the service to register a client, receiving callbacks
+ * from the service. The Message's replyTo field must be a Messenger of
+ * the client where callbacks should be sent.
+ */
+ public static final int MSG_REGISTER_CLIENT = 1;
+
+ /**
+ * Command to the service to unregister a client, ot stop receiving callbacks
+ * from the service. The Message's replyTo field must be a Messenger of
+ * the client as previously given with MSG_REGISTER_CLIENT.
+ */
+ public static final int MSG_UNREGISTER_CLIENT = 2;
+
+ /**
+ * Command to service to set a new value. This can be sent to the
+ * service to supply a new value, and will be sent by the service to
+ * any registered clients with the new value.
+ */
+ public static final int MSG_SET_VALUE = 3;
+
+ private LocationManager locationManager;
+ private LocationListener locationListener;
+
+
+ @Override
+ public void onCreate() {
+ notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
+ // Display a notification about us starting.
+ showNotification();
+
+ this.mobiAdsBatch = new MobiAdsBatch(this.getResources().getString(R.string.user_agent_web_service),
+ this.getResources().getString(R.string.encoded_web_service));
+
+ Criteria criteria = new Criteria();
+ criteria.setAccuracy(Criteria.ACCURACY_FINE);
+ criteria.setAltitudeRequired(false);
+ criteria.setBearingAccuracy(Criteria.NO_REQUIREMENT);
+ criteria.setBearingRequired(false);
+ criteria.setCostAllowed(false);
+ criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);
+ criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
+ criteria.setSpeedAccuracy(Criteria.ACCURACY_LOW);
+ criteria.setSpeedRequired(true);
+ criteria.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
+
+ // Acquire a reference to the system Location Manager
+ this.locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
+
+ // Define a listener that responds to location updates
+ this.locationListener = new LocationListener() {
+
+ public void onLocationChanged(Location location) {
+ // Called when a new location is found by the network location provider.
+ // This method is run by the main thread of this Dalvik process.
+ // Called when a new location is found by the network location provider.
+ MobiAdsService.this.mobiAdsBatch.makeUseOfNewLocation(location);
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ //1. Find out the provider state. (see Copilot.java code GPSLocationListener)
+ //2. If it is TEMPORARILY_UNAVAILABLE:
+ //2.1. locationManager.removeUpdates(locationListener); <--- Stop wasting GPS or GSM connections
+ //2.2. Launch Timer with TimerTask 30 or 60 seconds before to enable the locationManager to find out if the provider status changed.
+ //3. If OUT_OF_SERVICE
+ //3.1. locationManager.removeUpdates(locationListener); <--- Stop wasting GPS or GSM connections
+ //3.2. Launch Timer with TimerTask 30 or 60 seconds before to enable the locationManager to find out if the provider status changed.
+ //4. If AVAILABLE
+ // Nothing to do here.
+ //Just when we are in the second or third point we have to stop draining battery because it is useless.
+
+ }
+
+ public void onProviderEnabled(String provider) {}
+
+ public void onProviderDisabled(String provider) {}
+ };
+
+ // Register the listener with the Location Manager to receive location updates
+ locationManager.requestLocationUpdates(0, 10, criteria, locationListener, null);
+ }
+
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ @Override
+ public void onDestroy() {
+ // Cancel the persistent notification.
+ notificationManager.cancel(R.string.remote_service_started);
+
+ if (this.locationListener != null) {
+ this.locationManager.removeUpdates(this.locationListener);
+ }
+
+ if (this.mobiAdsBatch != null) {
+ this.mobiAdsBatch.endBatch();
+ }
+ }
+
+
+ /**
+ * Show a notification while this service is running.
+ */
+ private void showNotification() {
+ // In this sample, we'll use the same text for the ticker and the expanded notification
+ CharSequence text = getText(R.string.remote_service_started);
+
+ // Set the icon, scrolling text and timestamp
+ Notification notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis());
+
+ Intent intent = new Intent(this, MobiAdsMainActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ // The PendingIntent to launch our activity if the user selects this notification
+ PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+
+ Context context = getApplicationContext();
+
+ //notification.contentIntent = contentIntent;
+ // Set the info for the views that show in the notification panel.
+ //notification.defaults |= Notification.DEFAULT_VIBRATE;
+ //notification.ledARGB = 0xff00ff00;
+ //notification.ledOnMS = 300;
+ //notification.ledOffMS = 1000;
+ //notification.flags |= Notification.FLAG_SHOW_LIGHTS;
+ notification.flags |= Notification.FLAG_NO_CLEAR;
+ notification.setLatestEventInfo(context, getText(R.string.remote_service_label), text, contentIntent);
+
+ // Send the notification.
+ // We use a string id because it is a unique number. We use it later to cancel.
+ notificationManager.notify(R.string.remote_service_started, notification);
+ }
+}
--- /dev/null
+package de.android.mobiads.batch;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import android.location.Location;
+import android.net.http.AndroidHttpClient;
+import android.util.Log;
+
+public class MobiAdsBatch {
+ private static final String TAG = "MobiAdsBatch";
+ private static final int tasksMax = 10;
+ private final ExecutorService exec = Executors.newFixedThreadPool(tasksMax);
+ private final String encoded;
+ private final AndroidHttpClient httpClient;
+
+
+ public MobiAdsBatch (String userAgent, String encoded) {
+ this.encoded = encoded;
+
+ this.httpClient = AndroidHttpClient.newInstance(userAgent);
+ }
+
+
+ public void makeUseOfNewLocation(Location location) {
+
+ final String latitude = Double.toString(location.getLatitude());
+ final String longitude = Double.toString(location.getLongitude());
+ final String latitudeReplace = latitude.replace(".", ",");
+ final String longitudeReplace = longitude.replace(".", ",");
+ final String URLAuth = "http://users.mobiads.gumartinm.name/userfront.php/api/" + latitudeReplace + "/" + longitudeReplace + "/gpsads.json";
+ URL url = null;
+
+ try {
+ //RESTful WebService
+ url = new URL(URLAuth);
+ } catch (MalformedURLException e) {
+ Log.e(TAG, "Error while creating a URL", e);
+ return;
+ }
+
+ final Batch batch = new Batch(url);
+
+ this.exec.execute(batch);
+ }
+
+
+ public void endBatch() {
+ this.exec.shutdown();
+ }
+
+
+ private class Batch implements Runnable {
+
+ private Batch (URL url) {
+
+ }
+
+ @Override
+ public void run() {
+ // TODO Auto-generated method stub
+
+ }
+
+ }
+}
--- /dev/null
+package de.android.mobiads.provider;
+
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+public final class Indexer {
+ public static final String AUTHORITY = "de.android.mobiads.provider.IndexerProvider";
+
+ // This class cannot be instantiated
+ private Indexer() {
+ }
+
+ /**
+ * Indexer table contract
+ */
+ public static final class Index implements BaseColumns {
+
+ // This class cannot be instantiated
+ private Index() {}
+
+ /**
+ * The table name offered by this provider
+ */
+ public static final String TABLE_NAME = "indexer";
+
+ /**
+ * Column name for the path of the file
+ * <P>Type: TEXT</P>
+ */
+ public static final String COLUMN_NAME_PATH = "path";
+
+ /**
+ * Column name for the ad unique identifier number
+ * <P>Type: INTEGER</P>
+ */
+ public static final String COLUMN_NAME_ID_AD = "idad";
+
+ /**
+ * The default sort order for this table
+ */
+ public static final String DEFAULT_SORT_ORDER = Index._ID;
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of notes.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.index";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
+ * note.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.index";
+
+ /**
+ * The content URI base for a single index. Callers must
+ * append a numeric note id to this Uri to retrieve an index
+ */
+ public static final Uri CONTENT_ID_URI_BASE
+ = Uri.parse("content://de.android.mobiads.provider/indexer/");
+ }
+}
--- /dev/null
+package de.android.mobiads.provider;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+
+public class IndexerOpenHelper extends SQLiteOpenHelper {
+ // Used for debugging and logging
+ private static final String TAG = "IndexerOpenHelper";
+
+ private static final String DATABASE_NAME = "mobiads.db";
+ private static final int DATABASE_VERSION = 1;
+
+
+ IndexerOpenHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+
+ /**
+ *
+ * Creates the underlying database with table name and column names taken from the
+ * Indexer class.
+ */
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + Indexer.Index.TABLE_NAME + " ("
+ + Indexer.Index._ID + " INTEGER PRIMARY KEY, "
+ + Indexer.Index.COLUMN_NAME_ID_AD + " INTEGER" + " UNIQUE" + " NOT NULL,"
+ + Indexer.Index.COLUMN_NAME_PATH + " TEXT(15)" + " UNIQUE" + " NOT NULL"
+ + ");");
+ }
+
+
+ /**
+ *
+ * Demonstrates that the provider must consider what happens when the
+ * underlying datastore is changed. In this sample, the database is upgraded the database
+ * by destroying the existing data.
+ * A real application should upgrade the database in place.
+ */
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // Logs that the database is being upgraded
+ Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ + newVersion + ", which will destroy all old data");
+
+ // Kills the table and existing data
+ db.execSQL("DROP TABLE IF EXISTS " + Indexer.Index.TABLE_NAME);
+
+ // Recreates the database with a new version
+ onCreate(db);
+ }
+}
--- /dev/null
+package de.android.mobiads.provider;
+
+import java.util.HashMap;
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.text.TextUtils;
+
+/**
+ *
+ */
+public class IndexerProvider extends ContentProvider {
+ // Creates a UriMatcher object.
+ private static final UriMatcher sUriMatcher;
+
+ /**
+ * A projection map used to select columns from the database
+ */
+ private static HashMap<String, String> sIndexerProjectionMap;
+
+ // Handle to a new DatabaseHelper.
+ private IndexerOpenHelper mOpenHelper;
+
+ // The incoming URI matches the Notes URI pattern
+ private static final int INDEXER = 1;
+
+ // The incoming URI matches the Note ID URI pattern
+ private static final int INDEXER_ID = 2;
+
+ private static final int INDEXER_IDAD = 3;
+
+ static {
+
+ /*
+ * Creates and initializes the URI matcher
+ */
+ // Create a new instance
+ sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+ // Add a pattern that routes URIs terminated with "indexer" to a INDEXER operation
+ sUriMatcher.addURI("de.android.mobiads.provider", Indexer.Index.TABLE_NAME, INDEXER);
+
+ // Add a pattern that routes URIs terminated with "indexer" plus an integer
+ // to a index ID operation
+ sUriMatcher.addURI("de.android.mobiads.provider", Indexer.Index.TABLE_NAME + "/#", INDEXER_ID);
+
+ sUriMatcher.addURI("de.android.mobiads.provider", Indexer.Index.TABLE_NAME + "/" + Indexer.Index.COLUMN_NAME_ID_AD + "/#", INDEXER_IDAD);
+
+
+ /*
+ * Creates and initializes a projection map that returns all columns
+ */
+
+ // Creates a new projection map instance. The map returns a column name
+ // given a string. The two are usually equal.
+ sIndexerProjectionMap = new HashMap<String, String>();
+
+ // Maps the string "_ID" to the column name "_ID"
+ sIndexerProjectionMap.put(Indexer.Index._ID, Indexer.Index._ID);
+
+ // Maps "idad" to "idad"
+ sIndexerProjectionMap.put(Indexer.Index.COLUMN_NAME_ID_AD, Indexer.Index.COLUMN_NAME_ID_AD);
+
+ // Maps "path" to "path"
+ sIndexerProjectionMap.put(Indexer.Index.COLUMN_NAME_PATH, Indexer.Index.COLUMN_NAME_PATH);
+ }
+
+
+
+ /**
+ *
+ * Initializes the provider by creating a new DatabaseHelper. onCreate() is called
+ * automatically when Android creates the provider in response to a resolver request from a
+ * client.
+ */
+ @Override
+ public boolean onCreate() {
+
+ // Creates a new helper object. Note that the database itself isn't opened until
+ // something tries to access it, and it's only created if it doesn't already exist.
+ mOpenHelper = new IndexerOpenHelper(getContext());
+
+ // Assumes that any failures will be reported by a thrown exception.
+ return true;
+ }
+
+
+ /**
+ * This is called when a client calls
+ * {@link android.content.ContentResolver#delete(Uri, String, String[])}.
+ * Deletes records from the database. If the incoming URI matches the note ID URI pattern,
+ * this method deletes the one record specified by the ID in the URI. Otherwise, it deletes a
+ * a set of records. The record or records must also match the input selection criteria
+ * specified by where and whereArgs.
+ *
+ * If rows were deleted, then listeners are notified of the change.
+ * @return If a "where" clause is used, the number of rows affected is returned, otherwise
+ * 0 is returned. To delete all rows and get a row count, use "1" as the where clause.
+ * @throws IllegalArgumentException if the incoming URI pattern is invalid.
+ */
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ // Opens the database object in "write" mode.
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+
+ String finalWhere;
+
+ int count;
+
+ // Does the delete based on the incoming URI pattern.
+ switch (sUriMatcher.match(uri)) {
+ case INDEXER:
+ // If the incoming pattern matches the general pattern for notes, does a delete
+ // based on the incoming "where" columns and arguments.
+ count = db.delete(
+ Indexer.Index.TABLE_NAME, // The database table name
+ selection, // The incoming where clause column names
+ selectionArgs // The incoming where clause values
+ );
+ break;
+ case INDEXER_ID:
+ /*
+ * Starts a final WHERE clause by restricting it to the
+ * desired note ID.
+ */
+ finalWhere =
+ Indexer.Index._ID + // The ID column name
+ " = " + // test for equality
+ uri.getPathSegments().get(1); // the incoming note ID
+
+
+ // If there were additional selection criteria, append them to the final
+ // WHERE clause
+ if (selection != null) {
+ finalWhere = finalWhere + " AND " + selection;
+ }
+
+ // Performs the delete.
+ count = db.delete(
+ Indexer.Index.TABLE_NAME, // The database table name.
+ finalWhere, // The final WHERE clause
+ selectionArgs // The incoming where clause values.
+ );
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
+
+ return count;
+ }
+
+ /**
+ * This is called when a client calls {@link android.content.ContentResolver#getType(Uri)}.
+ * Returns the MIME data type of the URI given as a parameter.
+ *
+ * @param uri The URI whose MIME type is desired.
+ * @return The MIME type of the URI.
+ * @throws IllegalArgumentException if the incoming URI pattern is invalid.
+ */
+ @Override
+ public String getType(Uri uri) {
+ /**
+ * Chooses the MIME type based on the incoming URI pattern
+ */
+ switch (sUriMatcher.match(uri)) {
+ // If the pattern is for notes or live folders, returns the general content type.
+ case INDEXER:
+ return Indexer.Index.CONTENT_TYPE;
+
+ // If the pattern is for note IDs, returns the note ID content type.
+ case INDEXER_ID:
+ return Indexer.Index.CONTENT_ITEM_TYPE;
+
+ // If the URI pattern doesn't match any permitted patterns, throws an exception.
+ default:
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
+ }
+
+
+ /**
+ * This is called when a client calls
+ * {@link android.content.ContentResolver#insert(Uri, ContentValues)}.
+ * Inserts a new row into the database. This method sets up default values for any
+ * columns that are not included in the incoming map.
+ * If rows were inserted, then listeners are notified of the change.
+ * @return The row ID of the inserted row.
+ * @throws SQLException if the insertion fails.
+ */
+ @Override
+ public Uri insert(Uri uri, ContentValues initialValues) {
+ // A map to hold the new record's values.
+ ContentValues values;
+
+ // If the incoming values map is not null, uses it for the new values.
+ if (initialValues != null) {
+ values = new ContentValues(initialValues);
+
+ } else {
+ // Otherwise, create a new value map
+ values = new ContentValues();
+ }
+
+ // If the values map doesn't contain the path or ad identifier number.
+ if ((values.containsKey(Indexer.Index.COLUMN_NAME_PATH) == false) ||
+ (values.containsKey(Indexer.Index.COLUMN_NAME_ID_AD) == false)){
+ throw new SQLException("Missed parameter. Failed to insert row into " + uri);
+ }
+
+ // Opens the database object in "write" mode.
+ // This will trigger its creation if it doesn't already exist.
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+
+ // Performs the insert and returns the ID of the new index.
+ long rowId = db.insert(
+ Indexer.Index.TABLE_NAME, // The table to insert into.
+ null, // A hack, SQLite sets this column value to null if values is empty.
+ values // A map of column names, and the values to insert into the columns.
+ );
+
+ // If the insert succeeded, the row ID exists.
+ if (rowId > 0) {
+ // Creates a URI with the index ID pattern and the new row ID appended to it.
+ Uri noteUri = ContentUris.withAppendedId(Indexer.Index.CONTENT_ID_URI_BASE, rowId);
+
+ // Notifies observers registered against this provider that the data changed.
+ getContext().getContentResolver().notifyChange(noteUri, null);
+ return noteUri;
+ }
+
+ // If the insert didn't succeed, then the rowID is <= 0. Throws an exception.
+ throw new SQLException("Failed to insert row into " + uri);
+ }
+
+
+ /**
+ * This method is called when a client calls
+ * {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)}.
+ * Queries the database and returns a cursor containing the results.
+ *
+ * @return A cursor containing the results of the query. The cursor exists but is empty if
+ * the query returns no results or an exception occurs.
+ * @throws IllegalArgumentException if the incoming URI pattern is invalid.
+ */
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+
+ // Constructs a new query builder and sets its table name
+ SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ qb.setTables(Indexer.Index.TABLE_NAME);
+
+ /**
+ * Choose the projection and adjust the "where" clause based on URI pattern-matching.
+ */
+ switch (sUriMatcher.match(uri)) {
+ // If the incoming URI is for notes, chooses the Indexer projection
+ case INDEXER:
+ qb.setProjectionMap(sIndexerProjectionMap);
+
+ break;
+
+ /* If the incoming URI is for a single note identified by its ID, chooses the
+ * note ID projection, and appends "_ID = <noteID>" to the where clause, so that
+ * it selects that single note
+ */
+ case INDEXER_ID:
+ qb.setProjectionMap(sIndexerProjectionMap);
+ qb.appendWhere(
+ Indexer.Index._ID + // the name of the ID column
+ "=" +
+ // the position of the note ID itself in the incoming URI
+ uri.getPathSegments().get(1));
+ break;
+
+ case INDEXER_IDAD:
+ qb.setProjectionMap(sIndexerProjectionMap);
+ qb.appendWhere(
+ Indexer.Index.COLUMN_NAME_ID_AD + // the name of the ID column
+ "=" +
+ // the position of the Advertisement ID itself in the incoming URI
+ uri.getPathSegments().get(2));
+ break;
+ default:
+ // If the URI doesn't match any of the known patterns, throw an exception.
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
+
+ String orderBy;
+ // If no sort order is specified, uses the default
+ if (TextUtils.isEmpty(sortOrder)) {
+ orderBy = Indexer.Index.DEFAULT_SORT_ORDER;
+ } else {
+ // otherwise, uses the incoming sort order
+ orderBy = sortOrder;
+ }
+
+ // Opens the database object in "read" mode, since no writes need to be done.
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+
+ /*
+ * Performs the query. If no problems occur trying to read the database, then a Cursor
+ * object is returned; otherwise, the cursor variable contains null. If no records were
+ * selected, then the Cursor object is empty, and Cursor.getCount() returns 0.
+ */
+ Cursor c = qb.query(
+ db, // The database to query
+ projection, // The columns to return from the query
+ selection, // The columns for the where clause
+ selectionArgs, // The values for the where clause
+ null, // don't group the rows
+ null, // don't filter by row groups
+ orderBy // The sort order
+ );
+
+
+ // Tells the Cursor what URI to watch, so it knows when its source data changes
+ c.setNotificationUri(getContext().getContentResolver(), uri);
+ return c;
+ }
+
+ /**
+ * This is called when a client calls
+ * {@link android.content.ContentResolver#update(Uri,ContentValues,String,String[])}
+ * Updates records in the database. The column names specified by the keys in the values map
+ * are updated with new data specified by the values in the map. If the incoming URI matches the
+ * note ID URI pattern, then the method updates the one record specified by the ID in the URI;
+ * otherwise, it updates a set of records. The record or records must match the input
+ * selection criteria specified by where and whereArgs.
+ * If rows were updated, then listeners are notified of the change.
+ *
+ * @param uri The URI pattern to match and update.
+ * @param values A map of column names (keys) and new values (values).
+ * @param where An SQL "WHERE" clause that selects records based on their column values. If this
+ * is null, then all records that match the URI pattern are selected.
+ * @param whereArgs An array of selection criteria. If the "where" param contains value
+ * placeholders ("?"), then each placeholder is replaced by the corresponding element in the
+ * array.
+ * @return The number of rows updated.
+ * @throws IllegalArgumentException if the incoming URI pattern is invalid.
+ */
+ @Override
+ public int update(Uri uri, ContentValues values, String where,
+ String[] whereArgs) {
+
+ // Opens the database object in "write" mode.
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ int count;
+ String finalWhere;
+
+ // Does the update based on the incoming URI pattern
+ switch (sUriMatcher.match(uri)) {
+
+ // If the incoming URI matches the general notes pattern, does the update based on
+ // the incoming data.
+ case INDEXER:
+
+ // Does the update and returns the number of rows updated.
+ count = db.update(
+ Indexer.Index.TABLE_NAME, // The database table name.
+ values, // A map of column names and new values to use.
+ where, // The where clause column names.
+ whereArgs // The where clause column values to select on.
+ );
+ break;
+
+ // If the incoming URI matches a single note ID, does the update based on the incoming
+ // data, but modifies the where clause to restrict it to the particular note ID.
+ case INDEXER_ID:
+
+ // From the incoming URI, get the note ID
+ String noteId = uri.getPathSegments().get(1);
+
+ /*
+ * Starts creating the final WHERE clause by restricting it to the incoming
+ * note ID.
+ */
+ finalWhere =
+ Indexer.Index._ID + // The ID column name
+ " = " + // test for equality
+ noteId; // the incoming note ID
+
+ // If there were additional selection criteria, append them to the final WHERE
+ // clause
+ if (where !=null) {
+ finalWhere = finalWhere + " AND " + where;
+ }
+
+
+ // Does the update and returns the number of rows updated.
+ count = db.update(
+ Indexer.Index.TABLE_NAME, // The database table name.
+ values, // A map of column names and new values to use.
+ finalWhere, // The final WHERE clause to use
+ // placeholders for whereArgs
+ whereArgs // The where clause column values to select on, or
+ // null if the values are in the where argument.
+ );
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
+
+ /*Gets a handle to the content resolver object for the current context, and notifies it
+ * that the incoming URI changed. The object passes this along to the resolver framework,
+ * and observers that have registered themselves for the provider are notified.
+ */
+ getContext().getContentResolver().notifyChange(uri, null);
+
+ // Returns the number of rows updated.
+ return count;
+ }
+
+}