First steps implementing my MobiAds Android app.
authorgumartinm <gu.martinm@gmail.com>
Mon, 19 Mar 2012 23:06:35 +0000 (00:06 +0100)
committergumartinm <gu.martinm@gmail.com>
Mon, 19 Mar 2012 23:06:35 +0000 (00:06 +0100)
18 files changed:
Android/MobiAds/AndroidManifest.xml [new file with mode: 0644]
Android/MobiAds/gen/de/android/mobiads/R.java [new file with mode: 0644]
Android/MobiAds/proguard.cfg [new file with mode: 0644]
Android/MobiAds/project.properties [new file with mode: 0644]
Android/MobiAds/res/drawable-hdpi/alert_dialog_icon.png [new file with mode: 0755]
Android/MobiAds/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
Android/MobiAds/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
Android/MobiAds/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
Android/MobiAds/res/layout/main.xml [new file with mode: 0644]
Android/MobiAds/res/layout/mobiadsmain.xml [new file with mode: 0644]
Android/MobiAds/res/values/strings.xml [new file with mode: 0644]
Android/MobiAds/src/de/android/mobiads/MobiAdsLoginActivity.java [new file with mode: 0644]
Android/MobiAds/src/de/android/mobiads/MobiAdsMainActivity.java [new file with mode: 0644]
Android/MobiAds/src/de/android/mobiads/MobiAdsService.java [new file with mode: 0644]
Android/MobiAds/src/de/android/mobiads/batch/MobiAdsBatch.java [new file with mode: 0644]
Android/MobiAds/src/de/android/mobiads/provider/Indexer.java [new file with mode: 0644]
Android/MobiAds/src/de/android/mobiads/provider/IndexerOpenHelper.java [new file with mode: 0644]
Android/MobiAds/src/de/android/mobiads/provider/IndexerProvider.java [new file with mode: 0644]

diff --git a/Android/MobiAds/AndroidManifest.xml b/Android/MobiAds/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..41b37c2
--- /dev/null
@@ -0,0 +1,73 @@
+<?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
diff --git a/Android/MobiAds/gen/de/android/mobiads/R.java b/Android/MobiAds/gen/de/android/mobiads/R.java
new file mode 100644 (file)
index 0000000..417c50b
--- /dev/null
@@ -0,0 +1,52 @@
+/* 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;
+    }
+}
diff --git a/Android/MobiAds/proguard.cfg b/Android/MobiAds/proguard.cfg
new file mode 100644 (file)
index 0000000..b1cdf17
--- /dev/null
@@ -0,0 +1,40 @@
+-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 *;
+}
diff --git a/Android/MobiAds/project.properties b/Android/MobiAds/project.properties
new file mode 100644 (file)
index 0000000..8da376a
--- /dev/null
@@ -0,0 +1,11 @@
+# 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
diff --git a/Android/MobiAds/res/drawable-hdpi/alert_dialog_icon.png b/Android/MobiAds/res/drawable-hdpi/alert_dialog_icon.png
new file mode 100755 (executable)
index 0000000..fe54477
Binary files /dev/null and b/Android/MobiAds/res/drawable-hdpi/alert_dialog_icon.png differ
diff --git a/Android/MobiAds/res/drawable-hdpi/ic_launcher.png b/Android/MobiAds/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..8074c4c
Binary files /dev/null and b/Android/MobiAds/res/drawable-hdpi/ic_launcher.png differ
diff --git a/Android/MobiAds/res/drawable-ldpi/ic_launcher.png b/Android/MobiAds/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..1095584
Binary files /dev/null and b/Android/MobiAds/res/drawable-ldpi/ic_launcher.png differ
diff --git a/Android/MobiAds/res/drawable-mdpi/ic_launcher.png b/Android/MobiAds/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..a07c69f
Binary files /dev/null and b/Android/MobiAds/res/drawable-mdpi/ic_launcher.png differ
diff --git a/Android/MobiAds/res/layout/main.xml b/Android/MobiAds/res/layout/main.xml
new file mode 100644 (file)
index 0000000..1e03635
--- /dev/null
@@ -0,0 +1,50 @@
+<?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
diff --git a/Android/MobiAds/res/layout/mobiadsmain.xml b/Android/MobiAds/res/layout/mobiadsmain.xml
new file mode 100644 (file)
index 0000000..552d337
--- /dev/null
@@ -0,0 +1,60 @@
+<?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
diff --git a/Android/MobiAds/res/values/strings.xml b/Android/MobiAds/res/values/strings.xml
new file mode 100644 (file)
index 0000000..653249f
--- /dev/null
@@ -0,0 +1,26 @@
+<?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
diff --git a/Android/MobiAds/src/de/android/mobiads/MobiAdsLoginActivity.java b/Android/MobiAds/src/de/android/mobiads/MobiAdsLoginActivity.java
new file mode 100644 (file)
index 0000000..01435fe
--- /dev/null
@@ -0,0 +1,209 @@
+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
diff --git a/Android/MobiAds/src/de/android/mobiads/MobiAdsMainActivity.java b/Android/MobiAds/src/de/android/mobiads/MobiAdsMainActivity.java
new file mode 100644 (file)
index 0000000..84dfe06
--- /dev/null
@@ -0,0 +1,136 @@
+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));
+    }
+}
diff --git a/Android/MobiAds/src/de/android/mobiads/MobiAdsService.java b/Android/MobiAds/src/de/android/mobiads/MobiAdsService.java
new file mode 100644 (file)
index 0000000..baca137
--- /dev/null
@@ -0,0 +1,158 @@
+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);
+    }
+}
diff --git a/Android/MobiAds/src/de/android/mobiads/batch/MobiAdsBatch.java b/Android/MobiAds/src/de/android/mobiads/batch/MobiAdsBatch.java
new file mode 100644 (file)
index 0000000..9e77e37
--- /dev/null
@@ -0,0 +1,67 @@
+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
+                       
+               }
+               
+       }
+}
diff --git a/Android/MobiAds/src/de/android/mobiads/provider/Indexer.java b/Android/MobiAds/src/de/android/mobiads/provider/Indexer.java
new file mode 100644 (file)
index 0000000..623e503
--- /dev/null
@@ -0,0 +1,61 @@
+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/");
+    }
+}
diff --git a/Android/MobiAds/src/de/android/mobiads/provider/IndexerOpenHelper.java b/Android/MobiAds/src/de/android/mobiads/provider/IndexerOpenHelper.java
new file mode 100644 (file)
index 0000000..fff4ccc
--- /dev/null
@@ -0,0 +1,55 @@
+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);
+       }
+}
diff --git a/Android/MobiAds/src/de/android/mobiads/provider/IndexerProvider.java b/Android/MobiAds/src/de/android/mobiads/provider/IndexerProvider.java
new file mode 100644 (file)
index 0000000..4cf3b74
--- /dev/null
@@ -0,0 +1,422 @@
+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;
+       }
+
+}