From 6aacbe2713abc1a008dd41190a06125228a3bd90 Mon Sep 17 00:00:00 2001 From: gumartinm Date: Sun, 16 Dec 2012 01:43:44 +0100 Subject: [PATCH] Retrieving cookie from Service. Using Android inter process communication. --- .../MobiAdsReloaded/gen/de/android/mobiads/R.java | 62 +- Android/MobiAdsReloaded/res/values/strings.xml | 2 - .../src/de/android/mobiads/MobiAdsService.java | 72 +- .../src/de/android/mobiads/MobiAdsSettings.java | 132 --- .../src/de/android/mobiads/batch/MobiAdsBatch.java | 1 - .../src/de/android/mobiads/list/MobiAdsList.java | 1001 +++++++++++--------- 6 files changed, 600 insertions(+), 670 deletions(-) diff --git a/Android/MobiAdsReloaded/gen/de/android/mobiads/R.java b/Android/MobiAdsReloaded/gen/de/android/mobiads/R.java index 6a5ece9..7603546 100644 --- a/Android/MobiAdsReloaded/gen/de/android/mobiads/R.java +++ b/Android/MobiAdsReloaded/gen/de/android/mobiads/R.java @@ -49,44 +49,42 @@ public final class R { public static final int alert_dialog_not_logged=0x7f060005; public static final int app_description=0x7f060003; public static final int app_name=0x7f060002; - public static final int button_cancel=0x7f060011; - public static final int button_localads=0x7f060012; + public static final int button_cancel=0x7f06000f; + public static final int button_localads=0x7f060010; public static final int button_login=0x7f06000a; - public static final int button_messagebind=0x7f06000b; - public static final int button_messagelistlocalads=0x7f06000f; - public static final int button_messagestartservice=0x7f06000e; - public static final int button_messagestopservice=0x7f06000d; - public static final int button_messageunbind=0x7f06000c; - public static final int button_ok=0x7f060010; - public static final int desc=0x7f060020; - public static final int encoded_web_service=0x7f06001f; + public static final int button_messagelistlocalads=0x7f06000d; + public static final int button_messagestartservice=0x7f06000c; + public static final int button_messagestopservice=0x7f06000b; + public static final int button_ok=0x7f06000e; + public static final int desc=0x7f06001e; + public static final int encoded_web_service=0x7f06001d; public static final int error_dialog_connection_error=0x7f060006; - public static final int error_dialog_no_local_ads=0x7f060024; + public static final int error_dialog_no_local_ads=0x7f060022; public static final int error_dialog_userpwd_error=0x7f060007; public static final int header_bar=0x7f060000; - public static final int menuads_login=0x7f060023; - public static final int menuads_remove=0x7f060021; - public static final int menuads_settings=0x7f060022; - public static final int meters_update_rate_preference_summary=0x7f060028; - public static final int meters_update_rate_preference_title=0x7f060027; + public static final int menuads_login=0x7f060021; + public static final int menuads_remove=0x7f06001f; + public static final int menuads_settings=0x7f060020; + public static final int meters_update_rate_preference_summary=0x7f060026; + public static final int meters_update_rate_preference_title=0x7f060025; public static final int new_ads=0x7f060001; public static final int password=0x7f060009; - public static final int remote_service_content_empty_notification=0x7f060016; - public static final int remote_service_content_notification=0x7f060015; - public static final int remote_service_new_ads=0x7f060013; - public static final int remote_service_received_ad_notification=0x7f060014; - public static final int remote_service_started_notification=0x7f060017; - public static final int remote_service_stopped_notification=0x7f060018; - public static final int remote_service_title_notification=0x7f060019; - public static final int service_preference_title=0x7f060025; - public static final int service_preference_title_summary=0x7f060026; - public static final int time_update_rate_preference_summary=0x7f06002a; - public static final int time_update_rate_preference_title=0x7f060029; - public static final int url_api_web_services=0x7f06001b; - public static final int url_images=0x7f06001c; - public static final int url_login_web_service=0x7f06001a; - public static final int url_web=0x7f06001d; - public static final int user_agent_web_service=0x7f06001e; + public static final int remote_service_content_empty_notification=0x7f060014; + public static final int remote_service_content_notification=0x7f060013; + public static final int remote_service_new_ads=0x7f060011; + public static final int remote_service_received_ad_notification=0x7f060012; + public static final int remote_service_started_notification=0x7f060015; + public static final int remote_service_stopped_notification=0x7f060016; + public static final int remote_service_title_notification=0x7f060017; + public static final int service_preference_title=0x7f060023; + public static final int service_preference_title_summary=0x7f060024; + public static final int time_update_rate_preference_summary=0x7f060028; + public static final int time_update_rate_preference_title=0x7f060027; + public static final int url_api_web_services=0x7f060019; + public static final int url_images=0x7f06001a; + public static final int url_login_web_service=0x7f060018; + public static final int url_web=0x7f06001b; + public static final int user_agent_web_service=0x7f06001c; public static final int username=0x7f060008; } public static final class xml { diff --git a/Android/MobiAdsReloaded/res/values/strings.xml b/Android/MobiAdsReloaded/res/values/strings.xml index 050cfd3..eb33824 100644 --- a/Android/MobiAdsReloaded/res/values/strings.xml +++ b/Android/MobiAdsReloaded/res/values/strings.xml @@ -11,8 +11,6 @@ Username Password Log In - Bind Service - Unbind Service Stop Application Start Application List Your Ads diff --git a/Android/MobiAdsReloaded/src/de/android/mobiads/MobiAdsService.java b/Android/MobiAdsReloaded/src/de/android/mobiads/MobiAdsService.java index 8553316..258d8a3 100644 --- a/Android/MobiAdsReloaded/src/de/android/mobiads/MobiAdsService.java +++ b/Android/MobiAdsReloaded/src/de/android/mobiads/MobiAdsService.java @@ -1,7 +1,5 @@ package de.android.mobiads; -import java.util.ArrayList; - import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -14,48 +12,38 @@ 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.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; +import android.util.Log; import de.android.mobiads.batch.MobiAdsBatch; import de.android.mobiads.list.MobiAdsLatestList; public class MobiAdsService extends Service { + private static final String TAG = "MobiAdsService"; 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. + * Command to service to retrieve the current cookie value. This can be sent to the + * service to retrieve the cookie value, and will be sent by the service to + * any registered clients with the current value used by the service in order + * to connect with the Web Service. */ - public static final int MSG_UNREGISTER_CLIENT = 2; + public static final int MSG_GET_VALUE = 1; /** - * 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. + * Stores the current cookie value. */ - public static final int MSG_SET_VALUE = 3; + private String cookie = "WTF"; private LocationManager locationManager; private LocationListener locationListener; - private final ArrayList mClients = new ArrayList(); - /** Holds last value set by a client. */ - int mValue = 0; - /** * Meters update rate value used by LocationManager * and the user may change it using the settings activity. @@ -68,16 +56,6 @@ public class MobiAdsService extends Service { */ private long timeUpdateRateValue = 0; - /** - * 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; - } - } private final BroadcastReceiver receiver = new BroadcastReceiver() { @@ -87,7 +65,7 @@ public class MobiAdsService extends Service { //This will be run in the main thread of this service. It might be interesting to use a Handler //for this receiver implementing its own thread. :/ //TODO: If I do not want to have any trouble, to use a synchronize to access this code here and when - //receiving new ads. Besides you are using the same code xD. No time right now. I must improve my code + //receiving new ads in MobiAdsBatch class. Besides you are using the same code xD. No time right now. I must improve my code //but I am in a hurry. if(action.equals("de.android.mobiads.MOBIADSSERVICERECEIVER")){ updateNotification(); @@ -97,7 +75,7 @@ public class MobiAdsService extends Service { @Override public int onStartCommand(final Intent intent, final int flags, final int startId) { - final String cookie = intent.getStringExtra("cookie"); + cookie = intent.getStringExtra("cookie"); metersUpdateRateValue = Float.parseFloat(intent.getStringExtra("meters_update_rate_value")); timeUpdateRateValue = 60 * 1000 * Integer.parseInt(intent.getStringExtra("time_update_rate_value")); @@ -136,6 +114,7 @@ public class MobiAdsService extends Service { @Override public void onStatusChanged(final String provider, final int status, final Bundle extras) { + //TODO: //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 @@ -248,24 +227,15 @@ public class MobiAdsService extends Service { @Override public void handleMessage(final Message msg) { switch (msg.what) { - case MSG_REGISTER_CLIENT: - mClients.add(msg.replyTo); - break; - case MSG_UNREGISTER_CLIENT: - mClients.remove(msg.replyTo); - break; - case MSG_SET_VALUE: - mValue = msg.arg1; - for (int i=mClients.size()-1; i>=0; i--) { - try { - mClients.get(i).send(Message.obtain(null, - MSG_SET_VALUE, mValue, 0)); - } catch (final RemoteException e) { - // The client is dead. Remove it from the list; - // we are going through the list from back to front - // so this is safe to do inside the loop. - mClients.remove(i); - } + case MSG_GET_VALUE: + try { + final Bundle data = new Bundle(); + data.putString("cookie", MobiAdsService.this.cookie); + final Message returnMessage = Message.obtain(null, MSG_GET_VALUE); + returnMessage.setData(data); + msg.replyTo.send(returnMessage); + } catch (final RemoteException e) { + Log.wtf(TAG, "Client is dead", e); } break; default: diff --git a/Android/MobiAdsReloaded/src/de/android/mobiads/MobiAdsSettings.java b/Android/MobiAdsReloaded/src/de/android/mobiads/MobiAdsSettings.java index 18bd3c9..37cf164 100644 --- a/Android/MobiAdsReloaded/src/de/android/mobiads/MobiAdsSettings.java +++ b/Android/MobiAdsReloaded/src/de/android/mobiads/MobiAdsSettings.java @@ -5,22 +5,13 @@ import android.app.ActivityManager; import android.app.ActivityManager.RunningServiceInfo; import android.app.DialogFragment; import android.app.FragmentManager; -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.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceFragment; -import android.widget.TextView; -import android.widget.Toast; import de.android.mobiads.list.MobiAdsList; public class MobiAdsSettings extends Activity { @@ -69,7 +60,6 @@ public class MobiAdsSettings extends Activity { intent.putExtra("cookie", Cookie.getCookie()); intent.putExtra("meters_update_rate_value", metersUpdateRate.getValue()); intent.putExtra("time_update_rate_value", timeUpdateRate.getValue()); - //((MobiAdsSettings)getActivity()).doBindService(); getActivity().startService(intent); } else { @@ -79,7 +69,6 @@ public class MobiAdsSettings extends Activity { } } else { - //((MobiAdsSettings)getActivity()).doUnbindService(); getActivity().stopService(new Intent(getActivity(), MobiAdsService.class)); } return false; @@ -97,125 +86,4 @@ public class MobiAdsSettings extends Activity { return false; } } - - - - - - - - - /** 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; - - /** - * Handler of incoming messages from service. - */ - class IncomingHandler extends Handler { - @Override - public void handleMessage(final Message msg) { - switch (msg.what) { - case MobiAdsService.MSG_SET_VALUE: - mCallbackText.setText("Received from service: " + msg.arg1); - break; - default: - super.handleMessage(msg); - } - } - } - - /** - * Target we publish for clients to send messages to IncomingHandler. - */ - final Messenger mMessenger = new Messenger(new IncomingHandler()); - - /** - * Class for interacting with the main interface of the service. - */ - private final ServiceConnection mConnection = new ServiceConnection() { - - @Override - public void onServiceConnected(final ComponentName className, - final 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 (final 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(MobiAdsSettings.this, R.string.button_messagebind, - Toast.LENGTH_SHORT).show(); - } - - @Override - public void onServiceDisconnected(final 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(MobiAdsSettings.this, R.string.button_messageunbind, - Toast.LENGTH_SHORT).show(); - } - }; - - private 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. - bindService(new Intent(this, - MobiAdsService.class), mConnection, Context.BIND_AUTO_CREATE); - mIsBound = true; - mCallbackText.setText("Binding."); - } - - private void doUnbindService() { - if (mIsBound) { - // If we have received the service, and hence registered with - // it, then now is the time to unregister. - if (mService != null) { - try { - final Message msg = Message.obtain(null, - MobiAdsService.MSG_UNREGISTER_CLIENT); - msg.replyTo = mMessenger; - mService.send(msg); - } catch (final RemoteException e) { - // There is nothing special we need to do if the service - // has crashed. - } - } - - // Detach our existing connection. - unbindService(mConnection); - mIsBound = false; - mCallbackText.setText("Unbinding."); - } - } } diff --git a/Android/MobiAdsReloaded/src/de/android/mobiads/batch/MobiAdsBatch.java b/Android/MobiAdsReloaded/src/de/android/mobiads/batch/MobiAdsBatch.java index aeb8a75..18413df 100644 --- a/Android/MobiAdsReloaded/src/de/android/mobiads/batch/MobiAdsBatch.java +++ b/Android/MobiAdsReloaded/src/de/android/mobiads/batch/MobiAdsBatch.java @@ -45,7 +45,6 @@ public class MobiAdsBatch { private final AndroidHttpClient httpClient; private final Context context; private final String mobiAdsCookie; - private static final String USERS_SERVER = "http://companies.mobiads.gumartinm.name/uploads/images/"; public MobiAdsBatch (final String userAgent, final String encoded, final Context context, final String cookie) { diff --git a/Android/MobiAdsReloaded/src/de/android/mobiads/list/MobiAdsList.java b/Android/MobiAdsReloaded/src/de/android/mobiads/list/MobiAdsList.java index 18ae170..46536aa 100644 --- a/Android/MobiAdsReloaded/src/de/android/mobiads/list/MobiAdsList.java +++ b/Android/MobiAdsReloaded/src/de/android/mobiads/list/MobiAdsList.java @@ -6,8 +6,11 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; + import android.app.ActionBar; import android.app.Activity; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; @@ -23,11 +26,17 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.Loader; +import android.content.ServiceConnection; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; 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.text.TextUtils; import android.util.Log; import android.util.SparseBooleanArray; @@ -41,492 +50,580 @@ import android.widget.ListView; import android.widget.SearchView; import android.widget.SearchView.OnQueryTextListener; import de.android.mobiads.Cookie; +import de.android.mobiads.MobiAdsService; import de.android.mobiads.R; import de.android.mobiads.provider.Indexer; public class MobiAdsList extends Activity { - private BroadcastReceiver mReceiver; - - - @Override - protected void onCreate(Bundle savedInstanceState) { + private static final String TAG = "MobiAdsList"; + private BroadcastReceiver mReceiver; + + /** + * Target we publish for clients to send messages to IncomingHandler. + */ + private final Messenger mMessenger = new Messenger(new IncomingHandler()); + + @Override + protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); final ActionBar actionBar = getActionBar(); final MobiAdsListFragment list = new MobiAdsListFragment(); - + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE); actionBar.setTitle(getResources().getString(R.string.header_bar)); - //actionBar.setDisplayHomeAsUpEnabled(true); - - - FragmentManager fm = getFragmentManager(); + if (isMyServiceRunning()) { + this.doBindService(); + } + + + + final FragmentManager fm = getFragmentManager(); // Create the list fragment and add it as our sole content. if (fm.findFragmentById(android.R.id.content) == null) { fm.beginTransaction().add(android.R.id.content, list).commit(); } - - + + mReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - //This will be run in the main thread of this service. It might be interesting to use a Handler - //for this receiver implementing its own thread. :/ - if(action.equals("de.android.mobiads.MOBIADSLISTRECEIVER")){ - getLoaderManager().restartLoader(0, null, list); - } - } - }; - - IntentFilter filter = new IntentFilter(); + + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + //This will be run in the main thread of this service. It might be interesting to use a Handler + //for this receiver implementing its own thread. :/ + if(action.equals("de.android.mobiads.MOBIADSLISTRECEIVER")){ + getLoaderManager().restartLoader(0, null, list); + } + } + }; + + final IntentFilter filter = new IntentFilter(); filter.addAction("de.android.mobiads.MOBIADSLISTRECEIVER"); registerReceiver(mReceiver, filter); - + } - @Override - protected void onDestroy() { - unregisterReceiver(mReceiver); - super.onDestroy(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - super.onOptionsItemSelected(item); - Intent intent = null; + @Override + protected void onDestroy() { + unregisterReceiver(mReceiver); + super.onDestroy(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + super.onOptionsItemSelected(item); + Intent intent = null; switch (item.getItemId()) { case R.id.menuads_settings: - intent = new Intent("android.intent.action.MOBIADS"). - setComponent(new ComponentName("de.android.mobiads", "de.android.mobiads.MobiAdsSettings")); - this.startActivity(intent); + intent = new Intent("android.intent.action.MOBIADS"). + setComponent(new ComponentName("de.android.mobiads", "de.android.mobiads.MobiAdsSettings")); + this.startActivity(intent); return true; case R.id.menuads_login: - if (Cookie.getCookie() != null) { - createAlertDialog(R.string.alert_dialog_logged); - } - else { - intent = new Intent("android.intent.action.MOBIADS"). - setComponent(new ComponentName("de.android.mobiads", "de.android.mobiads.MobiAdsLoginActivity")); - this.startActivity(intent); - } - return true; + if (Cookie.getCookie() != null) { + createAlertDialog(R.string.alert_dialog_logged); + } + else { + intent = new Intent("android.intent.action.MOBIADS"). + setComponent(new ComponentName("de.android.mobiads", "de.android.mobiads.MobiAdsLoginActivity")); + this.startActivity(intent); + } + return true; default: return false; } - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - return super.onPrepareOptionsMenu(menu); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.menuads, menu); - - return true; - } - - public void onOptionsMenuClosed(Menu menu) { + } + + @Override + public boolean onPrepareOptionsMenu(final Menu menu) { + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + super.onCreateOptionsMenu(menu); + final MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menuads, menu); + + return true; + } + + @Override + public void onOptionsMenuClosed(final Menu menu) { super.onOptionsMenuClosed(menu); } - - /** - * A custom Loader that loads all of the installed applications. - */ - public static class AdsListLoader extends AsyncTaskLoader> { - private static final String TAG = "AdsListLoader"; - List mApps; - - public AdsListLoader(Context context) { - super(context); - } - - /** - * This is where the bulk of our work is done. This function is - * called in a background thread and should generate a new set of - * data to be published by the loader. - */ - @Override - public List loadInBackground() { - // Create corresponding array of entries and load their labels. - List entries = getAdsEntries(); - - return entries; - } - - private List getAdsEntries() { - final List entries = new ArrayList(); - final Uri uri = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer"); - final ContentValues values = new ContentValues(); - - Cursor cursor = getContext().getContentResolver().query(uri, null, null, null, null); - try { - if (cursor.moveToFirst()) { - do { - values.clear(); - Bitmap bitMap = null; - FileInputStream file = null; - try { - file = getContext().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."); - } - } - } - - boolean readStatus; - if ( cursor.getInt(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_IS_READ)) == 0) { - readStatus = false; - } - else { - readStatus = true; - } - - entries.add(new AdsEntry(cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_AD_NAME)), - cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_TEXT)), bitMap, - cursor.getInt(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_ID_AD)), - cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_URL)), - readStatus)); - }while (cursor.moveToNext()); - } - }finally { - cursor.close(); - } - - return entries; - } - - /** - * Called when there is new data to deliver to the client. The - * super class will take care of delivering it; the implementation - * here just adds a little more logic. - */ - @Override - public void deliverResult(List apps) { - mApps = apps; - - if (isStarted()) { - // If the Loader is currently started, we can immediately - // deliver its results. - super.deliverResult(apps); - } - } - - /** - * Handles a request to start the Loader. - */ - @Override - protected void onStartLoading() { - if (mApps != null) { - // If we currently have a result available, deliver it - // immediately. - deliverResult(mApps); - } - - if (takeContentChanged() || mApps == null) { - // If the data has changed since the last time it was loaded - // or is not currently available, start a load. - forceLoad(); - } - } - - /** - * Handles a request to cancel a load. - */ - @Override - public void onCanceled(List apps) { - super.onCanceled(apps); - - // At this point we can release the resources associated with 'apps' - // if needed. - } - - /** - * Handles a request to completely reset the Loader. - */ - @Override - protected void onReset() { - super.onReset(); - - // Ensure the loader is stopped - onStopLoading(); - - // At this point we can release the resources associated with 'apps' - // if needed. - if (mApps != null) { - mApps = null; - } - } - } - - public static class MobiAdsListFragment extends ListFragment implements OnQueryTextListener, - LoaderManager.LoaderCallbacks> { - AdsEntryAdapter mAdapter; - // If non-null, this is the current filter the user has provided. - String mCurFilter; - - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - ListView listView = getListView(); - - listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); - - - listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { - - @Override - public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { - final int checkedCount = getListView().getCheckedItemCount(); - switch (checkedCount) { - case 0: - mode.setSubtitle(null); - break; - case 1: - mode.setSubtitle("One item selected"); - break; - default: - mode.setSubtitle("" + checkedCount + " items selected"); - break; - } - } - - @Override - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - // Respond to clicks on the actions in the CAB - switch (item.getItemId()) { - case R.id.selectedmenu_remove: - SparseBooleanArray itemsPositions = getListView().getCheckedItemPositions(); - Collection aux = new ArrayList(mAdapter.getCount()); - for (int i=0; i< itemsPositions.size(); i++) { - if (itemsPositions.valueAt(i)) { - aux.add(mAdapter.getItem(itemsPositions.keyAt(i))); - } - } - if (!aux.isEmpty()) { - for(final AdsEntry entry : aux) { - removeAd(entry); - } - } - mode.finish(); // Action picked, so close the CAB - return true; - default: - return false; - } - } - - /** - * When selecting an item we remove the current action bar menu and we populate it with this one. - */ - @Override - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - MenuInflater inflater = mode.getMenuInflater(); - inflater.inflate(R.menu.selectedmenuads, menu); - final int checkedCount = getListView().getCheckedItemCount(); - switch (checkedCount) { - case 0: - mode.setSubtitle(null); - break; - case 1: - mode.setSubtitle("One item selected"); - break; - default: - mode.setSubtitle("" + checkedCount + " items selected"); - break; - } - return true; - } - - @Override - public void onDestroyActionMode(ActionMode mode) { - //Nothing to do here. - } - - @Override - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - // Here you can perform updates to the CAB due to - // an invalidate() request - return false; - } - }); - - setEmptyText("No downloaded Ads."); - - // We have a menu item to show in action bar. - setHasOptionsMenu(true); - - - mAdapter = new AdsEntryAdapter(getActivity(), R.layout.ads_entry_list_item); - - setListAdapter(mAdapter); - // Start out with a progress indicator. - setListShown(false); - - getLoaderManager().initLoader(0, null, this); - - } - - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - final AdsEntry entry = mAdapter.getItem(position); - - if (!entry.isRead()) { - setIsReadEntry(entry); - } - - //Change notification (if there is one) - Intent updateDatabase = new Intent("de.android.mobiads.MOBIADSSERVICERECEIVER"); - getActivity().sendBroadcast(updateDatabase); - - //This will update our view showing a nice black background for this item in our list :/ - mAdapter.notifyDataSetChanged(); - - //Going to open the web navigator whatever it is... - Uri uri = Uri.parse(entry.getURL()); - startActivity(new Intent(Intent.ACTION_VIEW, uri)); + + /** + * A custom Loader that loads all of the installed applications. + */ + public static class AdsListLoader extends AsyncTaskLoader> { + private static final String TAG = "AdsListLoader"; + List mApps; + + public AdsListLoader(final Context context) { + super(context); + } + + /** + * This is where the bulk of our work is done. This function is + * called in a background thread and should generate a new set of + * data to be published by the loader. + */ + @Override + public List loadInBackground() { + // Create corresponding array of entries and load their labels. + final List entries = getAdsEntries(); + + return entries; + } + + private List getAdsEntries() { + final List entries = new ArrayList(); + final Uri uri = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer"); + final ContentValues values = new ContentValues(); + + final Cursor cursor = getContext().getContentResolver().query(uri, null, null, null, null); + try { + if (cursor.moveToFirst()) { + do { + values.clear(); + Bitmap bitMap = null; + FileInputStream file = null; + try { + file = getContext().openFileInput(cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_PATH))); + bitMap = BitmapFactory.decodeStream(file); + } catch (final FileNotFoundException e) { + //Giving more chances to other ads + continue; + } catch (final IllegalArgumentException e) { + //Giving more chances to other ads + continue; + } + finally { + if (file != null) { + try { + file.close(); + } catch (final IOException e) { + Log.w(TAG, "Error while closing image file."); + } + } + } + + boolean readStatus; + if ( cursor.getInt(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_IS_READ)) == 0) { + readStatus = false; + } + else { + readStatus = true; + } + + entries.add(new AdsEntry(cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_AD_NAME)), + cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_TEXT)), bitMap, + cursor.getInt(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_ID_AD)), + cursor.getString(cursor.getColumnIndexOrThrow(Indexer.Index.COLUMN_NAME_URL)), + readStatus)); + }while (cursor.moveToNext()); + } + }finally { + cursor.close(); + } + + return entries; + } + + /** + * Called when there is new data to deliver to the client. The + * super class will take care of delivering it; the implementation + * here just adds a little more logic. + */ + @Override + public void deliverResult(final List apps) { + mApps = apps; + + if (isStarted()) { + // If the Loader is currently started, we can immediately + // deliver its results. + super.deliverResult(apps); + } + } + + /** + * Handles a request to start the Loader. + */ + @Override + protected void onStartLoading() { + if (mApps != null) { + // If we currently have a result available, deliver it + // immediately. + deliverResult(mApps); + } + + if (takeContentChanged() || mApps == null) { + // If the data has changed since the last time it was loaded + // or is not currently available, start a load. + forceLoad(); + } + } + + /** + * Handles a request to cancel a load. + */ + @Override + public void onCanceled(final List apps) { + super.onCanceled(apps); + + // At this point we can release the resources associated with 'apps' + // if needed. + } + + /** + * Handles a request to completely reset the Loader. + */ + @Override + protected void onReset() { + super.onReset(); + + // Ensure the loader is stopped + onStopLoading(); + + // At this point we can release the resources associated with 'apps' + // if needed. + if (mApps != null) { + mApps = null; + } + } + } + + public static class MobiAdsListFragment extends ListFragment implements OnQueryTextListener, + LoaderManager.LoaderCallbacks> { + AdsEntryAdapter mAdapter; + // If non-null, this is the current filter the user has provided. + String mCurFilter; + + + @Override + public void onActivityCreated(final Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + final ListView listView = getListView(); + + listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); + + + listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { + + @Override + public void onItemCheckedStateChanged(final ActionMode mode, final int position, final long id, final boolean checked) { + final int checkedCount = getListView().getCheckedItemCount(); + switch (checkedCount) { + case 0: + mode.setSubtitle(null); + break; + case 1: + mode.setSubtitle("One item selected"); + break; + default: + mode.setSubtitle("" + checkedCount + " items selected"); + break; + } + } + + @Override + public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) { + // Respond to clicks on the actions in the CAB + switch (item.getItemId()) { + case R.id.selectedmenu_remove: + final SparseBooleanArray itemsPositions = getListView().getCheckedItemPositions(); + final Collection aux = new ArrayList(mAdapter.getCount()); + for (int i=0; i< itemsPositions.size(); i++) { + if (itemsPositions.valueAt(i)) { + aux.add(mAdapter.getItem(itemsPositions.keyAt(i))); + } + } + if (!aux.isEmpty()) { + for(final AdsEntry entry : aux) { + removeAd(entry); + } + } + mode.finish(); // Action picked, so close the CAB + return true; + default: + return false; + } + } + + /** + * When selecting an item we remove the current action bar menu and we populate it with this one. + */ + @Override + public boolean onCreateActionMode(final ActionMode mode, final Menu menu) { + final MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.selectedmenuads, menu); + final int checkedCount = getListView().getCheckedItemCount(); + switch (checkedCount) { + case 0: + mode.setSubtitle(null); + break; + case 1: + mode.setSubtitle("One item selected"); + break; + default: + mode.setSubtitle("" + checkedCount + " items selected"); + break; + } + return true; + } + + @Override + public void onDestroyActionMode(final ActionMode mode) { + //Nothing to do here. + } + + @Override + public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) { + // Here you can perform updates to the CAB due to + // an invalidate() request + return false; + } + }); + + setEmptyText("No downloaded Ads."); + + // We have a menu item to show in action bar. + setHasOptionsMenu(true); + + + mAdapter = new AdsEntryAdapter(getActivity(), R.layout.ads_entry_list_item); + + setListAdapter(mAdapter); + // Start out with a progress indicator. + setListShown(false); + + getLoaderManager().initLoader(0, null, this); + + } + + @Override + public void onListItemClick(final ListView l, final View v, final int position, final long id) { + final AdsEntry entry = mAdapter.getItem(position); + + if (!entry.isRead()) { + setIsReadEntry(entry); + } + + //Change notification (if there is one) + final Intent updateDatabase = new Intent("de.android.mobiads.MOBIADSSERVICERECEIVER"); + getActivity().sendBroadcast(updateDatabase); + + //This will update our view showing a nice black background for this item in our list :/ + mAdapter.notifyDataSetChanged(); + + //Going to open the web navigator whatever it is... + final Uri uri = Uri.parse(entry.getURL()); + startActivity(new Intent(Intent.ACTION_VIEW, uri)); + } + + private void setIsReadEntry(final AdsEntry entry) { + final Uri uriUpdate = Uri.parse("content://" + "de.android.mobiads.provider" + + "/" + "indexer/idad/" + entry.getIdAd()); + final ContentValues values = new ContentValues(); + + values.put(Indexer.Index.COLUMN_NAME_IS_READ, Integer.valueOf(1)); + + getActivity().getContentResolver().update(uriUpdate, values, null, null); + + entry.setIsRead(true); + } + + private void removeAd(final AdsEntry entry) { + final int idAd = entry.getIdAd(); + final Uri uriDelete = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer" + "/idad/" + idAd); + + getActivity().getContentResolver().delete(uriDelete, null, null); + mAdapter.remove(entry); + + //Change notification (if there is one) + final Intent updateDatabase = new Intent("de.android.mobiads.MOBIADSSERVICERECEIVER"); + getActivity().sendBroadcast(updateDatabase); + + mAdapter.notifyDataSetChanged(); + } + + /** + * When setHasOptionsMenu(true) we populate the action bar with this menu. It is merged to the + * current action bar menu (if there is no one) + */ + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + // Place an action bar item for searching. + final MenuItem item = menu.add("Search"); + + item.setIcon(android.R.drawable.ic_menu_search); + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + final SearchView sv = new SearchView(getActivity()); + sv.setOnQueryTextListener(this); + item.setActionView(sv); + } + + @Override + public Loader> onCreateLoader(final int id, final Bundle args) { + // This is called when a new Loader needs to be created. This + // sample only has one Loader with no arguments, so it is simple. + return new AdsListLoader(getActivity()); + } + + @Override + public void onLoadFinished(final Loader> loader, final List data) { + mAdapter.setData(data); + + // The list should now be shown. + if (isResumed()) { + setListShown(true); + } else { + setListShownNoAnimation(true); + } + } + + @Override + public void onLoaderReset(final Loader> loader) { + mAdapter.setData(null); } - - private void setIsReadEntry(final AdsEntry entry) { - final Uri uriUpdate = Uri.parse("content://" + "de.android.mobiads.provider" + - "/" + "indexer/idad/" + entry.getIdAd()); - final ContentValues values = new ContentValues(); - - values.put(Indexer.Index.COLUMN_NAME_IS_READ, new Integer(1)); - - getActivity().getContentResolver().update(uriUpdate, values, null, null); - - entry.setIsRead(true); - } - - private void removeAd(final AdsEntry entry) { - int idAd = entry.getIdAd(); - final Uri uriDelete = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer" + "/idad/" + idAd); - - getActivity().getContentResolver().delete(uriDelete, null, null); - mAdapter.remove(entry); - - //Change notification (if there is one) - Intent updateDatabase = new Intent("de.android.mobiads.MOBIADSSERVICERECEIVER"); - getActivity().sendBroadcast(updateDatabase); - - mAdapter.notifyDataSetChanged(); - } - - /** - * When setHasOptionsMenu(true) we populate the action bar with this menu. It is merged to the - * current action bar menu (if there is no one) - */ - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - // Place an action bar item for searching. - final MenuItem item = menu.add("Search"); - - item.setIcon(android.R.drawable.ic_menu_search); - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - SearchView sv = new SearchView(getActivity()); - sv.setOnQueryTextListener(this); - item.setActionView(sv); - } - - @Override - public Loader> onCreateLoader(int id, Bundle args) { - // This is called when a new Loader needs to be created. This - // sample only has one Loader with no arguments, so it is simple. - return new AdsListLoader(getActivity()); - } - - @Override - public void onLoadFinished(Loader> loader, List data) { - mAdapter.setData(data); - - // The list should now be shown. - if (isResumed()) { - setListShown(true); - } else { - setListShownNoAnimation(true); - } - } - - @Override - public void onLoaderReset(final Loader> loader) { - mAdapter.setData(null); - } - - @Override - public boolean onQueryTextSubmit(final String query) { - // Don't care about this. - return true; - } - - @Override - public boolean onQueryTextChange(final String newText) { - // Called when the action bar search text has changed. Update - // the search filter, and restart the loader to do a new query - // with this filter. - mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; - getLoaderManager().restartLoader(0, null, this); - return true; - } - } - - private void createAlertDialog(int title) { + + @Override + public boolean onQueryTextSubmit(final String query) { + // Don't care about this. + return true; + } + + @Override + public boolean onQueryTextChange(final String newText) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; + getLoaderManager().restartLoader(0, null, this); + return true; + } + } + + private void createAlertDialog(final int title) { final DialogFragment newFragment = AlertDialogFragment.newInstance(title); - + newFragment.show(getFragmentManager(), "alertDialog"); } - - //Create a helper for this or at least write its own file. - public static class AlertDialogFragment extends DialogFragment { - - public static AlertDialogFragment newInstance(int title) { - final 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(android.R.drawable.ic_dialog_alert) - .setTitle(title) - .setPositiveButton(R.string.button_ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - - } - } - ) - .create(); - } - } + + //Create a helper for this or at least write its own file. + public static class AlertDialogFragment extends DialogFragment { + + public static AlertDialogFragment newInstance(final int title) { + final AlertDialogFragment frag = new AlertDialogFragment(); + + final Bundle args = new Bundle(); + + args.putInt("title", title); + frag.setArguments(args); + + return frag; + } + + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + final int title = getArguments().getInt("title"); + + return new AlertDialog.Builder(getActivity()) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(title) + .setPositiveButton(R.string.button_ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int whichButton) { + + } + } + ) + .create(); + } + } + + private boolean isMyServiceRunning() { + final ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + for (final RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if (MobiAdsService.class.getName().equals(service.service.getClassName())) { + return true; + } + } + return false; + } + + /** + * Handler of incoming messages from service. + */ + class IncomingHandler extends Handler { + //TODO: If the answer from the service takes too long (and the user is fast enough), + //this activity is going to think there is not cookie. Is there any solution for this issue? + @Override + public void handleMessage(final Message msg) { + //Running in the main thread of this activity. + switch (msg.what) { + case MobiAdsService.MSG_GET_VALUE: + Cookie.setCookie(msg.getData().getString("cookie")); + MobiAdsList.this.doUnbindService(); + break; + default: + super.handleMessage(msg); + } + } + } + + /** + * Class for interacting with the main interface of the service. + */ + private final ServiceConnection mConnection = new ServiceConnection() { + /** Messenger for communicating with service. */ + Messenger mService = null; + + @Override + public void onServiceConnected(final ComponentName className, + final 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); + + try { + final Message msg = Message.obtain(null, MobiAdsService.MSG_GET_VALUE); + msg.replyTo = mMessenger; + mService.send(msg); + } catch (final RemoteException e) { + Log.w(TAG, "Unexpected service crash", e); + } + } + + @Override + public void onServiceDisconnected(final ComponentName className) { + // This is called when the connection with the service has been + // unexpectedly disconnected -- that is, its process crashed. + } + }; + + private 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. + bindService(new Intent(this, + MobiAdsService.class), mConnection, Context.BIND_AUTO_CREATE); + } + + private void doUnbindService() { + // Hence registered with the service now is the time to unregister. + // Detach our existing connection. + unbindService(mConnection); + } } -- 2.1.4