Latest changes in Android MobiAds application.
authorgumartinm <gustavo@gumartinm.name>
Fri, 8 Jun 2012 07:05:58 +0000 (09:05 +0200)
committergumartinm <gustavo@gumartinm.name>
Fri, 8 Jun 2012 07:05:58 +0000 (09:05 +0200)
15 files changed:
Android/MobiAds/AndroidManifest.xml
Android/MobiAds/gen/de/android/mobiads/R.java
Android/MobiAds/res/layout/main.xml
Android/MobiAds/res/layout/mobiadsnewadslist.xml [new file with mode: 0644]
Android/MobiAds/res/menu/menuads.xml [new file with mode: 0644]
Android/MobiAds/res/values/strings.xml
Android/MobiAds/src/de/android/mobiads/MobiAdsLoginActivity.java
Android/MobiAds/src/de/android/mobiads/MobiAdsMainActivity.java
Android/MobiAds/src/de/android/mobiads/MobiAdsService.java
Android/MobiAds/src/de/android/mobiads/batch/MobiAdsBatch.java
Android/MobiAds/src/de/android/mobiads/list/MobiAdsListActivity.java
Android/MobiAds/src/de/android/mobiads/list/MobiAdsNewAdsActivity.java [new file with mode: 0644]
Android/MobiAds/src/de/android/mobiads/provider/Indexer.java
Android/MobiAds/src/de/android/mobiads/provider/IndexerOpenHelper.java
Android/MobiAds/src/de/android/mobiads/provider/IndexerProvider.java

index a6b0675..f13b828 100644 (file)
@@ -22,7 +22,6 @@
             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.DEFAULT" />
             </intent-filter>
         </activity>
+        
+        <activity
+            android:label="@string/app_name"
+            android:name=".list.MobiAdsNewAdsActivity"
+            android:theme="@android:style/Theme.Black" 
+            android:screenOrientation="portrait"
+            android:configChanges="touchscreen|keyboard" >
+            <intent-filter>
+                <action android:name="android.intent.action.MOBIADSNEWADS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
                
         <service
-                   android:name=".MobiAdsService"
-               android:process=":mobiadsservice" >
+                   android:name=".MobiAdsService" >
         </service>
         
         <provider 
@@ -72,8 +82,7 @@
                android:permission="android.permission.MOBIADS"
                android:readPermission="android.permission.READ_MOBIADS"
                android:syncable="false"
-               android:writePermission="android.permission.WRITE_MOBIADS"
-               android:process=":mobiadsservice" >
+               android:writePermission="android.permission.WRITE_MOBIADS">
             <grant-uri-permission android:pathPattern=".*" />
                </provider>
         
index cfb7c06..a0ac68e 100644 (file)
@@ -16,20 +16,19 @@ public final class R {
         public static final int wheelnotification=0x7f020002;
     }
     public static final class id {
-        public static final int ads_entry_icon=0x7f05000f;
-        public static final int ads_entry_text=0x7f050011;
-        public static final int ads_entry_title=0x7f050010;
+        public static final int ads_entry_icon=0x7f05000e;
+        public static final int ads_entry_text=0x7f050010;
+        public static final int ads_entry_title=0x7f05000f;
         public static final int button_bind=0x7f050007;
-        public static final int button_lislocalads=0x7f05000e;
-        public static final int button_startservice=0x7f05000c;
-        public static final int button_stopservice=0x7f05000a;
+        public static final int button_lislocalads=0x7f05000d;
+        public static final int button_startservice=0x7f05000b;
+        public static final int button_stopservice=0x7f050009;
         public static final int button_unbind=0x7f050008;
-        public static final int cancel_button=0x7f050005;
         public static final int frameLayout1=0x7f050000;
         public static final int frameLayout2=0x7f050003;
-        public static final int frameLayout3=0x7f050009;
-        public static final int frameLayout4=0x7f05000b;
-        public static final int frameLayout5=0x7f05000d;
+        public static final int frameLayout3=0x7f050005;
+        public static final int frameLayout4=0x7f05000a;
+        public static final int frameLayout5=0x7f05000c;
         public static final int list=0x7f050006;
         public static final int login_button=0x7f050004;
         public static final int password=0x7f050002;
@@ -39,32 +38,39 @@ public final class R {
         public static final int main=0x7f030000;
         public static final int mobiadslist=0x7f030001;
         public static final int mobiadsmain=0x7f030002;
-        public static final int news_entry_list_item=0x7f030003;
+        public static final int mobiadsnewadslist=0x7f030003;
+        public static final int news_entry_list_item=0x7f030004;
     }
     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=0x7f04000f;
-        public static final int button_login=0x7f040008;
-        public static final int button_messagebind=0x7f040009;
-        public static final int button_messagelistlocalads=0x7f04000d;
-        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=0x7f04000e;
-        public static final int desc=0x7f040017;
-        public static final int encoded_web_service=0x7f040016;
-        public static final int error_dialog_connection_error=0x7f040004;
-        public static final int error_dialog_userpwd_error=0x7f040005;
+        public static final int alert_dialog_cancel=0x7f040004;
+        public static final int app_description=0x7f040003;
+        public static final int app_name=0x7f040002;
+        public static final int button_cancel=0x7f040010;
+        public static final int button_localads=0x7f040011;
+        public static final int button_login=0x7f040009;
+        public static final int button_messagebind=0x7f04000a;
+        public static final int button_messagelistlocalads=0x7f04000e;
+        public static final int button_messagestartservice=0x7f04000d;
+        public static final int button_messagestopservice=0x7f04000c;
+        public static final int button_messageunbind=0x7f04000b;
+        public static final int button_ok=0x7f04000f;
+        public static final int desc=0x7f04001d;
+        public static final int encoded_web_service=0x7f04001c;
+        public static final int error_dialog_connection_error=0x7f040005;
+        public static final int error_dialog_userpwd_error=0x7f040006;
         public static final int hello=0x7f040000;
-        public static final int password=0x7f040007;
-        public static final int remote_service_label=0x7f040012;
-        public static final int remote_service_started=0x7f040010;
-        public static final int remote_service_stopped=0x7f040011;
-        public static final int url_login_web_service=0x7f040013;
-        public static final int url_web=0x7f040014;
-        public static final int user_agent_web_service=0x7f040015;
-        public static final int username=0x7f040006;
+        public static final int new_ads=0x7f040001;
+        public static final int password=0x7f040008;
+        public static final int remote_service_content_empty_notification=0x7f040015;
+        public static final int remote_service_content_notification=0x7f040014;
+        public static final int remote_service_new_ads=0x7f040012;
+        public static final int remote_service_received_ad_notification=0x7f040013;
+        public static final int remote_service_started_notification=0x7f040016;
+        public static final int remote_service_stopped_notification=0x7f040017;
+        public static final int remote_service_title_notification=0x7f040018;
+        public static final int url_login_web_service=0x7f040019;
+        public static final int url_web=0x7f04001a;
+        public static final int user_agent_web_service=0x7f04001b;
+        public static final int username=0x7f040007;
     }
 }
index 1e03635..e045770 100644 (file)
@@ -1,10 +1,9 @@
 <?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">
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:weightSum="1" >
     
     <FrameLayout 
        android:id="@+id/frameLayout1" 
@@ -21,7 +20,7 @@
        
        <EditText
                android:id="@+id/password"
-               android:password="true"
+               android:inputType="textPassword"
                android:singleLine="true"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
        <Button
                android:id="@+id/login_button"
                android:onClick="onClickLogin"
-           android:layout_height="wrap_content
+           android:layout_height="70dp
            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"/>
+    <FrameLayout 
+        android:layout_width="match_parent" 
+        android:id="@+id/frameLayout3" 
+        android:layout_height="30dp">
+    </FrameLayout>
+       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:orientation="horizontal" 
+         android:layout_width="fill_parent"
+         android:layout_height="fill_parent">
+         <Button android:layout_weight="1" 
+             android:layout_height="wrap_content" 
+             android:layout_width="0dip"
+             android:onClick="onClickLocalAds"
+             android:text="@string/button_localads" />
+         <Button android:layout_weight="1"
+             android:layout_height="wrap_content" 
+             android:layout_width="0dip"
+             android:onClick="onClickCancel"
+             android:text="@string/button_cancel" />
+    </LinearLayout>
+       
        
 </LinearLayout>
\ No newline at end of file
diff --git a/Android/MobiAds/res/layout/mobiadsnewadslist.xml b/Android/MobiAds/res/layout/mobiadsnewadslist.xml
new file mode 100644 (file)
index 0000000..d5a1517
--- /dev/null
@@ -0,0 +1,16 @@
+<?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:orientation="vertical" >
+
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/new_ads" />
+    
+    <ListView android:id="@+id/list"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/Android/MobiAds/res/menu/menuads.xml b/Android/MobiAds/res/menu/menuads.xml
new file mode 100644 (file)
index 0000000..9467d9d
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+      <item android:id="@+id/menuads"
+          android:title="string"
+          android:titleCondensed="string"
+          android:icon="@[package:]drawable/drawable_resource_name"
+          android:onClick="method name"
+          android:showAsAction=["ifRoom" | "never" | "withText" | "always" | "collapseActionView"]
+          android:actionLayout="@[package:]layout/layout_resource_name"
+          android:actionViewClass="class name"
+          android:actionProviderClass="class name"
+          android:alphabeticShortcut="string"
+          android:numericShortcut="string"
+          android:checkable=["true" | "false"]
+          android:visible=["true" | "false"]
+          android:enabled=["true" | "false"]
+          android:menuCategory=["container" | "system" | "secondary" | "alternative"]
+          android:orderInCategory="integer" />
+    <group android:id="@[+][package:]id/resource name"
+           android:checkableBehavior=["none" | "all" | "single"]
+           android:visible=["true" | "false"]
+           android:enabled=["true" | "false"]
+           android:menuCategory=["container" | "system" | "secondary" | "alternative"]
+           android:orderInCategory="integer" >
+        <item />
+    </group>
+    <item >
+        <menu>
+          <item />
+        </menu>
+    </item>
+    
+
+</menu>
\ No newline at end of file
index 8a0a490..d5ed866 100644 (file)
@@ -2,6 +2,7 @@
 <resources>
 
     <string name="hello">Android MobiAds!</string>
+    <string name="new_ads">Latest received Ads</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="button_messagelistlocalads">List Your Ads</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="button_localads">Local Ads</string>
+    <string name="remote_service_new_ads"> new Ads downloaded for you.</string>
+    <string name="remote_service_received_ad_notification">Received Ad</string>
+    <string name="remote_service_content_notification">New Ads waiting for you</string>
+    <string name="remote_service_content_empty_notification">No new Ads waiting for you</string>
+    <string name="remote_service_started_notification">MobiAds Service Started</string>
+    <string name="remote_service_stopped_notification">MobiAds Service Stopped</string>
+    <string name="remote_service_title_notification">MobiAds Service</string>
     <string name="url_login_web_service">http://users.mobiads.gumartinm.name/userfront.php/api/login/auth.json</string>
     <string name="url_web">users.mobiads.gumartinm.name</string>
     <string name="user_agent_web_service">MobieAds/1.0</string>
index 5d9318a..2145382 100644 (file)
@@ -52,7 +52,7 @@ public class MobiAdsLoginActivity extends Activity {
                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);
@@ -90,6 +90,7 @@ public class MobiAdsLoginActivity extends Activity {
                                                        setComponent(new ComponentName("de.android.mobiads", "de.android.mobiads.MobiAdsMainActivity"));
                                        intent.putExtra("cookie", cookie);
                                        this.startActivity(intent);
+                                       this.finish();
                        } 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);
@@ -115,6 +116,12 @@ public class MobiAdsLoginActivity extends Activity {
         }
     }
     
+    public void onClickLocalAds(View v) {
+       Intent intent = new Intent("android.intent.action.MOBIADSLIST").
+                               setComponent(new ComponentName("de.android.mobiads", "de.android.mobiads.list.MobiAdsListActivity"));
+               this.startActivity(intent);
+    }
+    
     public void onClickCancel(View v) {
        createAlertDialog(R.string.alert_dialog_cancel);
     }
index 2fc737d..9befd15 100644 (file)
@@ -1,34 +1,22 @@
 package de.android.mobiads;
 
 import android.app.Activity;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
 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;
 
 public class MobiAdsMainActivity extends Activity {
-       /** For showing and hiding our notification. */
-    private NotificationManager notificationManager;
-    /** Messenger for communicating with service. */
-    Messenger mService = null;
+    /** Communicating with local service. */
+    MobiAdsService mBoundService = null;
     /** Flag indicating whether we have called bind on the service. */
     boolean mIsBound;
     /**
      * Target we publish for clients to send messages to IncomingHandler.
      */
-    final Messenger mMessenger = new Messenger(new IncomingHandler());
-    /**TODO: I should send a message to the service to find out if the service is running instead of this boolean field.*/
-    private boolean isEnabledService;
     private static String cookie;
 
        
@@ -61,66 +49,30 @@ public class MobiAdsMainActivity extends Activity {
     
     @Override
     public void onResume() {
-       if (this.isEnabledService) {
-               this.showNotification(0);
-       }
        super.onResume();
     }
     
     /**
-     * Handler of incoming messages from service.
-     */
-    class IncomingHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MobiAdsService.MSG_SET_VALUE:
-                    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
+               // 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);
-
-            // 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.
-            }
+            // interact with the service.  Because we have bound to a explicit
+            // service that we know is running in our own process, we can
+            // cast its IBinder to a concrete class and directly access it.
+            mBoundService = ((MobiAdsService.LocalBinder)service).getService();
         }
 
         public void onServiceDisconnected(ComponentName className) {
-            // This is called when the connection with the service has been
+               // This is called when the connection with the service has been
             // unexpectedly disconnected -- that is, its process crashed.
-            mService = null;
+            // Because it is running in our same process, we should never
+            // see this happen.
+            mBoundService = null;
+
         }
     };
 
@@ -128,9 +80,8 @@ public class MobiAdsMainActivity extends Activity {
         // 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, 
+       mIsBound = bindService(new Intent(MobiAdsMainActivity.this, 
                        MobiAdsService.class), mConnection, Context.BIND_AUTO_CREATE);
-        mIsBound = true;
     }
 
     
@@ -145,15 +96,12 @@ public class MobiAdsMainActivity extends Activity {
     
     public void onClickStopService(View v) {
        this.stopService(new Intent(MobiAdsMainActivity.this, MobiAdsService.class));
-       this.isEnabledService = false;
     }
     
     
     public void onClickStartService(View v) {
        Intent intent = new Intent(MobiAdsMainActivity.this, MobiAdsService.class);
         intent.putExtra("cookie", MobiAdsMainActivity.cookie);
-        this.notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
-        this.isEnabledService = true;
        this.startService(intent);
     }
     
@@ -162,31 +110,4 @@ public class MobiAdsMainActivity extends Activity {
                                setComponent(new ComponentName("de.android.mobiads", "de.android.mobiads.list.MobiAdsListActivity"));
                this.startActivity(intent);
     }
-    
-    /**
-     * Show a notification while this service is running.
-     */
-    public void showNotification(int level) {        
-
-        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);
-        
-
-        // Set the icon, scrolling text and timestamp
-        Notification.Builder notificationBuilder = new Notification.Builder(getApplicationContext()).
-                                                                                               setSmallIcon(R.drawable.wheelnotification, level).
-                                                                                                       setTicker(getText(R.string.remote_service_started)).
-                                                                                                               setWhen(System.currentTimeMillis()).
-                                                                                                                       setContentText(getText(R.string.remote_service_started)).
-                                                                                                                               setContentTitle(getText(R.string.remote_service_label)).
-                                                                                                                                       setContentIntent(contentIntent);
-        Notification notification = notificationBuilder.getNotification();
-        notification.flags |= Notification.FLAG_NO_CLEAR;
-
-        // 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);
-    }
 }
index 6004670..d326621 100644 (file)
@@ -1,6 +1,7 @@
 package de.android.mobiads;
 
 import de.android.mobiads.batch.MobiAdsBatch;
+import de.android.mobiads.list.MobiAdsNewAdsActivity;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -11,6 +12,7 @@ import android.location.Criteria;
 import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 
@@ -41,6 +43,18 @@ public class MobiAdsService extends Service {
     
     private LocationManager locationManager;
     private LocationListener locationListener;
+    
+    /**
+     * Class for clients to access.  Because we know this service always
+     * runs in the same process as its clients, we don't need to deal with
+     * IPC.
+     */
+    public class LocalBinder extends Binder {
+        MobiAdsService getService() {
+            return MobiAdsService.this;
+        }
+    }
+
         
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
@@ -102,8 +116,15 @@ public class MobiAdsService extends Service {
         
         notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
         // Display a notification about us starting.
-        showNotification(0);
-        
+        int noReadCount = 0;
+        CharSequence contentText;
+        if ((noReadCount = this.mobiAdsBatch.noReadAdsCount()) == 0) {
+               contentText = getText(R.string.remote_service_content_empty_notification);
+        }
+        else {
+               contentText = getText(R.string.remote_service_content_notification);
+        }
+        showNotification(0, noReadCount, contentText);
         return super.onStartCommand(intent, flags, startId);
     }
     
@@ -117,7 +138,7 @@ public class MobiAdsService extends Service {
        @Override
     public void onDestroy() {
         // Cancel the persistent notification.
-               notificationManager.cancel(R.string.remote_service_started);
+               notificationManager.cancel(R.string.remote_service_title_notification);
                
         if (this.locationListener != null) {
                this.locationManager.removeUpdates(this.locationListener);      
@@ -132,27 +153,27 @@ public class MobiAdsService extends Service {
        /**
      * Show a notification while this service is running.
      */
-    public void showNotification(int level) {        
+    public void showNotification(final int level, final int noReadAds, CharSequence contentText) {        
 
-        Intent intent =  new Intent(this, MobiAdsMainActivity.class);
+        Intent intent =  new Intent(this, MobiAdsNewAdsActivity.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);
-        
-
+                
         // Set the icon, scrolling text and timestamp
         Notification.Builder notificationBuilder = new Notification.Builder(getApplicationContext()).
                                                                                                setSmallIcon(R.drawable.wheelnotification, level).
-                                                                                                       setTicker(getText(R.string.remote_service_started)).
+                                                                                                       setTicker(getText(R.string.remote_service_started_notification)).
                                                                                                                setWhen(System.currentTimeMillis()).
-                                                                                                                       setContentText(getText(R.string.remote_service_started)).
-                                                                                                                               setContentTitle(getText(R.string.remote_service_label)).
-                                                                                                                                       setContentIntent(contentIntent);
+                                                                                                                       setContentText(contentText).
+                                                                                                                               setContentTitle(getText(R.string.remote_service_title_notification)).
+                                                                                                                                       setNumber(noReadAds).
+                                                                                                                                               setContentIntent(contentIntent);
         Notification notification = notificationBuilder.getNotification();
         notification.flags |= Notification.FLAG_NO_CLEAR;
 
         // 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);
+        notificationManager.notify(R.string.remote_service_title_notification, notification);
     }
 }
index 5170e4a..4237189 100644 (file)
@@ -32,6 +32,7 @@ import android.net.Uri;
 import android.net.http.AndroidHttpClient;
 import android.util.Log;
 import de.android.mobiads.MobiAdsService;
+import de.android.mobiads.R;
 import de.android.mobiads.provider.Indexer;
 
 public class MobiAdsBatch {
@@ -117,7 +118,19 @@ public class MobiAdsBatch {
                                                if ((uriInsert = updatedIndexer(objects)) != null) {
                                                        try {
                                                                downloadAds((String)objects.get("image"), (String) objects.get("id"));
-                                                               ((MobiAdsService)MobiAdsBatch.this.context).showNotification(1);
+                                                               int noReadCount = 0;
+                                                       CharSequence contentText;
+                                                       if ((noReadCount =  MobiAdsBatch.this.noReadAdsCount()) == 0) {
+                                                               contentText = ((MobiAdsService)MobiAdsBatch.this.context).
+                                                                                                       getText(R.string.remote_service_content_empty_notification);
+                                                       }
+                                                       else {
+                                                               contentText = ((MobiAdsService)MobiAdsBatch.this.context).
+                                                                                                       getText(R.string.remote_service_content_notification);
+                                                       }
+                                                               ((MobiAdsService)MobiAdsBatch.this.context).
+                                                                               showNotification(0, noReadCount, contentText);
+
                                                        } catch (Throwable e1) {
                                                                //In case of any error, remove the index database and the file
                                                                //or chunk successfully stored before the error.
@@ -266,6 +279,8 @@ public class MobiAdsBatch {
                                //getContentResolver().query method never returns Cursor with null value.
                                //TODO: review my code in order to find more cases like this. :(
                                //Be aware with the RunTimeExceptions. Apparently Java needs try/catch blocks in everywhere...
+                               //TODO this method outside updatedIndexer. It is all about semantic and good design. No time sorry...
+                               //Open an issue about improving my code some day...
                                Cursor cursor = MobiAdsBatch.this.context.getContentResolver().query(uri, null, null, null, null);
                                try {
                                        if (!cursor.moveToFirst()) {
@@ -275,6 +290,7 @@ public class MobiAdsBatch {
                                                values.put(Indexer.Index.COLUMN_NAME_PATH, (String) objects.get("id"));
                                                values.put(Indexer.Index.COLUMN_NAME_TEXT, (String) objects.get("text"));
                                                values.put(Indexer.Index.COLUMN_NAME_URL, (String) objects.get("link"));
+                                               values.put(Indexer.Index.COLUMN_NAME_IS_READ, new Integer(0));
                                                //This method may throw SQLiteException (as a RunTimeException). So, without a try/catch block
                                                //there could be a leaked cursor...
                                                //TODO: review code looking for more cases like this one...
@@ -287,4 +303,20 @@ public class MobiAdsBatch {
                        return updated;
                }
        }
+       
+       
+       public int noReadAdsCount() {
+               Uri uri = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer" + "/isRead/");
+               
+               Cursor cursor = MobiAdsBatch.this.context.getContentResolver().query(uri, null, null, null, null);
+               int count = 0; 
+               
+               try {
+                       count = cursor.getCount();
+               } finally {
+                       cursor.close();
+               }
+               
+               return count;
+       }
 }
index 32ca262..45a4300 100644 (file)
@@ -5,33 +5,34 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-
-import de.android.mobiads.MobiAdsMainActivity;
-import de.android.mobiads.R;
-import de.android.mobiads.provider.Indexer;
 import android.app.Activity;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
-import android.os.Bundle;
 import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.MenuInflater;
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ListView;
+import de.android.mobiads.R;
+import de.android.mobiads.provider.Indexer;
 
 public class MobiAdsListActivity extends Activity {
        private static final String TAG = "MobiAdsListActivity";
        
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    public void onResume() {
+        super.onResume();
         setContentView(R.layout.mobiadslist);
         
         // Setup the list view
@@ -39,6 +40,7 @@ public class MobiAdsListActivity extends Activity {
         final AdsEntryAdapter newsEntryAdapter = new AdsEntryAdapter(this, R.layout.news_entry_list_item);
         newsEntryListView.setAdapter(newsEntryAdapter);
         
+        this.registerForContextMenu(newsEntryListView);
         // Populate the list, through the adapter. Should I populate the whole list right now? I do not think so...
         // Find out a way to populate this list just when it is required... :/
         for(final AdsEntry entry : getAdsEntries()) {
@@ -59,19 +61,23 @@ public class MobiAdsListActivity extends Activity {
     private List<AdsEntry> getAdsEntries() {
        final List<AdsEntry> entries = new ArrayList<AdsEntry>();
        final Uri uri = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer");
+       final ContentValues values = new ContentValues();
        
        Cursor cursor = this.getContentResolver().query(uri, null, null, null, null);
        try {
                        if (cursor.moveToFirst()) {
                                do {
+                                       values.clear();
                                        Bitmap bitMap = null;
                                        FileInputStream file = null;
                                        try {
                                                file = this.openFileInput(cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_PATH)));
                                                bitMap = BitmapFactory.decodeStream(file);
                                        } catch (FileNotFoundException e) {
+                                               //Giving more chances to other ads
                                                continue;
                                        } catch (IllegalArgumentException e) {
+                                               //Giving more chances to other ads
                                                continue;
                                        }
                                        finally {
@@ -84,13 +90,54 @@ public class MobiAdsListActivity extends Activity {
                                                }
                                        }
                                        entries.add(new AdsEntry(cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_URL)), 
-                                                       cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_TEXT)), bitMap));
+                                                       cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_TEXT)), bitMap));                       
+                                       if (cursor.getInt(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_IS_READ)) == 0)
+                                       {
+                                               values.put(Indexer.Index.COLUMN_NAME_IS_READ, new Integer(1));
+                                               Uri uriUpdate = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer/" + 
+                                                                                                               cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index._ID)));
+                                               getContentResolver().update(uriUpdate, values, null, null);
+                                       }
                                }while (cursor.moveToNext());
                        } 
        }finally {
                                cursor.close();
                }
        
+       showNotification(0, 0, getText(R.string.remote_service_content_empty_notification));
+       
        return entries;
     }
+    
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+        super.onCreateContextMenu(menu, v, menuInfo);
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.menuads, menu);
+    }
+
+    
+    public void showNotification(final int level, final int noReadAds, CharSequence contentText) {        
+       NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
+        Intent intent =  new Intent(this, MobiAdsNewAdsActivity.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);
+                
+        // Set the icon, scrolling text and timestamp
+        Notification.Builder notificationBuilder = new Notification.Builder(getApplicationContext()).
+                                                                                               setSmallIcon(R.drawable.wheelnotification, level).
+                                                                                                       setTicker(getText(R.string.remote_service_started_notification)).
+                                                                                                               setWhen(System.currentTimeMillis()).
+                                                                                                                       setContentText(contentText).
+                                                                                                                               setContentTitle(getText(R.string.remote_service_title_notification)).
+                                                                                                                                       setNumber(noReadAds).
+                                                                                                                                               setContentIntent(contentIntent);
+        Notification notification = notificationBuilder.getNotification();
+        notification.flags |= Notification.FLAG_NO_CLEAR;
+
+        // 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_title_notification, notification);
+    }
 }
\ No newline at end of file
diff --git a/Android/MobiAds/src/de/android/mobiads/list/MobiAdsNewAdsActivity.java b/Android/MobiAds/src/de/android/mobiads/list/MobiAdsNewAdsActivity.java
new file mode 100644 (file)
index 0000000..60f0910
--- /dev/null
@@ -0,0 +1,133 @@
+package de.android.mobiads.list;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import de.android.mobiads.R;
+import de.android.mobiads.provider.Indexer;
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.AdapterView.OnItemClickListener;
+
+public class MobiAdsNewAdsActivity extends Activity {
+       private static final String TAG = "MobiAdsNewAdsActivity";
+       
+        @Override
+           public void onResume() {
+               super.onResume();
+               setContentView(R.layout.mobiadsnewadslist);
+               
+               // Setup the list view
+               final ListView newsEntryListView = (ListView) findViewById(R.id.list);
+               final AdsEntryAdapter newsEntryAdapter = new AdsEntryAdapter(this, R.layout.news_entry_list_item);
+               newsEntryListView.setAdapter(newsEntryAdapter);
+               
+               // Populate the list, through the adapter. Should I populate the whole list right now? I do not think so...
+               // Find out a way to populate this list just when it is required... :/
+               for(final AdsEntry entry : getAdsEntries()) {
+                       newsEntryAdapter.add(entry);
+               }
+               
+               newsEntryListView.setOnItemClickListener(new OnItemClickListener() {
+
+                               @Override
+                               public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                                       Uri uri = Uri.parse(newsEntryAdapter.getItem(position).getTitle());
+                                       startActivity(new Intent(Intent.ACTION_VIEW, uri));
+                               }
+               });
+               
+           }
+           
+           private List<AdsEntry> getAdsEntries() {
+               final List<AdsEntry> entries = new ArrayList<AdsEntry>();
+               final Uri uri = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer" + "/isRead/");
+               final ContentValues values = new ContentValues();
+
+               Cursor cursor = this.getContentResolver().query(uri, null, null, null, null);
+               try {
+                               if (cursor.moveToFirst()) {
+                                       do {
+                                               values.clear();
+                                               Bitmap bitMap = null;
+                                               FileInputStream file = null;
+                                               
+                                               try {
+                                                       file = this.openFileInput(cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_PATH)));
+                                                       bitMap = BitmapFactory.decodeStream(file);
+                                               } catch (FileNotFoundException e) {
+                                                       //Giving more chances to other ads
+                                                       continue;
+                                               } catch (IllegalArgumentException e) {
+                                                       //Giving more chances to other ads
+                                                       continue;
+                                               }
+                                               finally {
+                                                       if (file != null) {
+                                                               try {
+                                                                       file.close();
+                                                               } catch (IOException e) {
+                                                                       Log.w(TAG, "Error while closing image file.");
+                                                               }
+                                                       }
+                                               }
+                                               entries.add(new AdsEntry(cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_URL)), 
+                                                               cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_TEXT)), bitMap));
+
+                                               
+                                               cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_PATH));
+                                               values.put(Indexer.Index.COLUMN_NAME_IS_READ, new Integer(1));
+                                               Uri uriUpdate = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer/" + 
+                                                                                                               cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index._ID)));
+                                               getContentResolver().update(uriUpdate, values, null, null);
+                                       }while (cursor.moveToNext());
+                               } 
+               }finally {
+                                       cursor.close();
+                       }
+               
+
+               showNotification(0, 0, getText(R.string.remote_service_content_empty_notification));
+               
+               return entries;
+           }
+           
+           public void showNotification(final int level, final int noReadAds, CharSequence contentText) {        
+               NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
+               Intent intent =  new Intent(this, MobiAdsNewAdsActivity.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);
+                       
+               // Set the icon, scrolling text and timestamp
+               Notification.Builder notificationBuilder = new Notification.Builder(getApplicationContext()).
+                                                                                                       setSmallIcon(R.drawable.wheelnotification, level).
+                                                                                                               setTicker(getText(R.string.remote_service_started_notification)).
+                                                                                                                       setWhen(System.currentTimeMillis()).
+                                                                                                                               setContentText(contentText).
+                                                                                                                                       setContentTitle(getText(R.string.remote_service_title_notification)).
+                                                                                                                                               setNumber(noReadAds).
+                                                                                                                                                       setContentIntent(contentIntent);
+               Notification notification = notificationBuilder.getNotification();
+               notification.flags |= Notification.FLAG_NO_CLEAR;
+
+               // 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_title_notification, notification);
+           }
+}
index fb4cd4f..5e3e866 100644 (file)
@@ -48,6 +48,13 @@ public final class Indexer {
         public static final String COLUMN_NAME_URL = "url";
         
         /**
+         * Column name for the Sqlite3 integer as boolean field. <br>
+         * It let us know if the ad was already read by the user or not.
+         * <P>Type: TEXT</P>
+         */
+        public static final String COLUMN_NAME_IS_READ = "isRead";
+        
+        /**
          * The default sort order for this table
          */
         public static final String DEFAULT_SORT_ORDER = Index._ID;
index acaaaff..aa0d270 100644 (file)
@@ -30,7 +30,8 @@ public class IndexerOpenHelper extends SQLiteOpenHelper {
                                + Indexer.Index.COLUMN_NAME_ID_AD + " INTEGER" + " UNIQUE" + " NOT NULL, "
                                + Indexer.Index.COLUMN_NAME_PATH + " TEXT(15)" + " UNIQUE" + " NOT NULL, "
                                + Indexer.Index.COLUMN_NAME_URL + " TEXT(2000)" + " NOT NULL, "
-                               + Indexer.Index.COLUMN_NAME_TEXT + " TEXT(255)" + " NOT NULL"
+                               + Indexer.Index.COLUMN_NAME_TEXT + " TEXT(255)" + " NOT NULL, "
+                               + Indexer.Index.COLUMN_NAME_IS_READ + " INTEGER" + " NOT NULL "
                                + ");");
        }
 
index 6ac3c21..caebab5 100644 (file)
@@ -37,6 +37,8 @@ public class IndexerProvider extends ContentProvider {
     
     private static final int INDEXER_IDAD = 3;
     
+    private static final int NOREAD = 4;
+    
     static {
        
        /*
@@ -54,6 +56,7 @@ public class IndexerProvider extends ContentProvider {
         
         sUriMatcher.addURI("de.android.mobiads.provider", Indexer.Index.TABLE_NAME + "/" + Indexer.Index.COLUMN_NAME_ID_AD + "/#", INDEXER_IDAD);
         
+        sUriMatcher.addURI("de.android.mobiads.provider", Indexer.Index.TABLE_NAME + "/" + Indexer.Index.COLUMN_NAME_IS_READ, NOREAD);
         
         /*
          * Creates and initializes a projection map that returns all columns
@@ -75,6 +78,8 @@ public class IndexerProvider extends ContentProvider {
         sIndexerProjectionMap.put(Indexer.Index.COLUMN_NAME_TEXT, Indexer.Index.COLUMN_NAME_TEXT);
         
         sIndexerProjectionMap.put(Indexer.Index.COLUMN_NAME_URL, Indexer.Index.COLUMN_NAME_URL);
+        
+        sIndexerProjectionMap.put(Indexer.Index.COLUMN_NAME_IS_READ, Indexer.Index.COLUMN_NAME_IS_READ);
     }
  
     
@@ -217,7 +222,8 @@ public class IndexerProvider extends ContentProvider {
         if ((values.containsKey(Indexer.Index.COLUMN_NAME_PATH) == false) || 
                (values.containsKey(Indexer.Index.COLUMN_NAME_ID_AD) == false) || 
                (values.containsKey(Indexer.Index.COLUMN_NAME_TEXT) == false) || 
-               (values.containsKey(Indexer.Index.COLUMN_NAME_URL) == false)){
+               (values.containsKey(Indexer.Index.COLUMN_NAME_URL) == false) ||
+               (values.containsKey(Indexer.Index.COLUMN_NAME_IS_READ) == false)){
                throw new SQLException("Missed parameter. Failed to insert row into " + uri);
         }      
         
@@ -296,6 +302,10 @@ public class IndexerProvider extends ContentProvider {
                           // the position of the Advertisement ID itself in the incoming URI
                           uri.getPathSegments().get(2));
                        break;
+               case NOREAD:
+                       qb.setProjectionMap(sIndexerProjectionMap);
+                       qb.appendWhere(Indexer.Index.COLUMN_NAME_IS_READ + " = " + "0");
+                       break;
                default:
                    // If the URI doesn't match any of the known patterns, throw an exception.
                    throw new IllegalArgumentException("Unknown URI " + uri);
@@ -414,7 +424,22 @@ public class IndexerProvider extends ContentProvider {
                                               // null if the values are in the where argument.
                 );
                 break;
-                       
+                
+               case NOREAD:
+                       finalWhere = Indexer.Index.COLUMN_NAME_IS_READ + " = " + "0";
+                       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);
         }