My first Android FragmentList.
authorgumartinm <gustavo@gumartinm.name>
Sun, 17 Jun 2012 02:28:51 +0000 (04:28 +0200)
committergumartinm <gustavo@gumartinm.name>
Sun, 17 Jun 2012 02:28:51 +0000 (04:28 +0200)
It looks like a nice implementation.

Android/MobiAdsTabs/gen/de/android/mobiads/R.java
Android/MobiAdsTabs/res/layout/ads_entry_list_item.xml [new file with mode: 0644]
Android/MobiAdsTabs/res/layout/mobiadslist.xml [deleted file]
Android/MobiAdsTabs/res/layout/news_entry_list_item.xml [deleted file]
Android/MobiAdsTabs/res/values/strings.xml
Android/MobiAdsTabs/src/de/android/mobiads/FragmentStack.java [deleted file]
Android/MobiAdsTabs/src/de/android/mobiads/MobiAdsPreferences.java
Android/MobiAdsTabs/src/de/android/mobiads/MobiAdsTabsActivity.java
Android/MobiAdsTabs/src/de/android/mobiads/list/MobiAdsList.java [new file with mode: 0644]
Android/MobiAdsTabs/src/de/android/mobiads/list/MobiAdsListFragment.java [deleted file]
Android/MobiAdsTabs/src/de/android/mobiads/list/MobiAdsNewAdsActivity.java

index 02eb0bd..1deec00 100644 (file)
@@ -15,23 +15,22 @@ public final class R {
         public static final int wheelnotification=0x7f020001;
     }
     public static final class id {
-        public static final int ads_entry_icon=0x7f070006;
-        public static final int ads_entry_text=0x7f070008;
-        public static final int ads_entry_title=0x7f070007;
-        public static final int frameLayout1=0x7f070000;
-        public static final int frameLayout2=0x7f070003;
-        public static final int list=0x7f070005;
-        public static final int login_button=0x7f070004;
+        public static final int ads_entry_icon=0x7f070000;
+        public static final int ads_entry_text=0x7f070002;
+        public static final int ads_entry_title=0x7f070001;
+        public static final int frameLayout1=0x7f070003;
+        public static final int frameLayout2=0x7f070006;
+        public static final int list=0x7f070008;
+        public static final int login_button=0x7f070007;
         public static final int menuadsremove=0x7f070009;
-        public static final int password=0x7f070002;
-        public static final int username=0x7f070001;
+        public static final int password=0x7f070005;
+        public static final int username=0x7f070004;
     }
     public static final class layout {
-        public static final int login=0x7f030000;
-        public static final int main=0x7f030001;
-        public static final int mobiadslist=0x7f030002;
+        public static final int ads_entry_list_item=0x7f030000;
+        public static final int login=0x7f030001;
+        public static final int main=0x7f030002;
         public static final int mobiadsnewadslist=0x7f030003;
-        public static final int news_entry_list_item=0x7f030004;
     }
     public static final class menu {
         public static final int menuads=0x7f060000;
@@ -52,6 +51,7 @@ public final class R {
         public static final int desc=0x7f05001d;
         public static final int encoded_web_service=0x7f05001c;
         public static final int error_dialog_connection_error=0x7f050005;
+        public static final int error_dialog_no_local_ads=0x7f05001f;
         public static final int error_dialog_userpwd_error=0x7f050006;
         public static final int header_bar=0x7f050000;
         public static final int menuads_remove=0x7f05001e;
diff --git a/Android/MobiAdsTabs/res/layout/ads_entry_list_item.xml b/Android/MobiAdsTabs/res/layout/ads_entry_list_item.xml
new file mode 100644 (file)
index 0000000..13a01c3
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Layout for individual ads entries in a list -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+    
+    <!-- Icon shown next to the title/text -->
+    <ImageView
+        android:id="@+id/ads_entry_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:padding="3dp"
+        android:orientation="vertical"
+        android:contentDescription="@string/desc"/>
+    
+    <!-- Title of the ads entry -->
+    <TextView
+        android:id="@+id/ads_entry_title"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@id/ads_entry_icon"
+        android:layout_alignTop="@id/ads_entry_icon"
+           android:layout_margin="5dp"
+        android:textSize="14sp"
+        android:textStyle="bold" />
+    
+    <!-- Text of our entry -->
+    <TextView
+        android:id="@+id/ads_entry_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignLeft="@id/ads_entry_title"
+        android:layout_below="@id/ads_entry_title" 
+        android:textSize="12sp" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/Android/MobiAdsTabs/res/layout/mobiadslist.xml b/Android/MobiAdsTabs/res/layout/mobiadslist.xml
deleted file mode 100644 (file)
index 2fb5935..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?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" />
-    
-    <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/MobiAdsTabs/res/layout/news_entry_list_item.xml b/Android/MobiAdsTabs/res/layout/news_entry_list_item.xml
deleted file mode 100644 (file)
index 13a01c3..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!-- Layout for individual ads entries in a list -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:orientation="vertical">
-    
-    <!-- Icon shown next to the title/text -->
-    <ImageView
-        android:id="@+id/ads_entry_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentLeft="true"
-        android:padding="3dp"
-        android:orientation="vertical"
-        android:contentDescription="@string/desc"/>
-    
-    <!-- Title of the ads entry -->
-    <TextView
-        android:id="@+id/ads_entry_title"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        android:layout_toRightOf="@id/ads_entry_icon"
-        android:layout_alignTop="@id/ads_entry_icon"
-           android:layout_margin="5dp"
-        android:textSize="14sp"
-        android:textStyle="bold" />
-    
-    <!-- Text of our entry -->
-    <TextView
-        android:id="@+id/ads_entry_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignLeft="@id/ads_entry_title"
-        android:layout_below="@id/ads_entry_title" 
-        android:textSize="12sp" />
-
-</RelativeLayout>
\ No newline at end of file
index d78b3e6..c1dd817 100644 (file)
@@ -31,4 +31,5 @@
     <string name="encoded_web_service">UTF-8</string>
     <string name="desc">description</string>
     <string name="menuads_remove">Remove</string>
+    <string name="error_dialog_no_local_ads">You have no downloaded ads.</string>
 </resources>
\ No newline at end of file
diff --git a/Android/MobiAdsTabs/src/de/android/mobiads/FragmentStack.java b/Android/MobiAdsTabs/src/de/android/mobiads/FragmentStack.java
deleted file mode 100644 (file)
index 9e77f27..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package de.android.mobiads;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentTransaction;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.TextView;
-
-public class FragmentStack extends Activity {
-
-
-    public static class CountingFragment extends Fragment {
-        int mNum;
-
-        /**
-         * Create a new instance of CountingFragment, providing "num"
-         * as an argument.
-         */
-        static CountingFragment newInstance(int num) {
-            CountingFragment f = new CountingFragment();
-
-            // Supply num input as an argument.
-            Bundle args = new Bundle();
-            args.putInt("num", num);
-            f.setArguments(args);
-
-            return f;
-        }
-
-        /**
-         * When creating, retrieve this instance's number from its arguments.
-         */
-        @Override
-        public void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            mNum = getArguments() != null ? getArguments().getInt("num") : 1;
-        }
-
-        /**
-         * The Fragment's UI is just a simple text view showing its
-         * instance number.
-         */
-//        @Override
-//        public View onCreateView(LayoutInflater inflater, ViewGroup container,
-//                Bundle savedInstanceState) {
-//            View v = inflater.inflate(R.layout.logintab, container, false);
-//            View tv = v.findViewById(R.id.text);
-//            ((TextView)tv).setText("Fragment #" + mNum);
-//            tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
-//            return v;
-//        }
-    }
-
-}
index 92ffd98..5033dfb 100644 (file)
@@ -11,9 +11,9 @@ import android.preference.PreferenceFragment;
 
 public class MobiAdsPreferences extends PreferenceFragment {
 
-       @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+       @Override 
+       public void onActivityCreated(Bundle savedInstanceState) {
+               super.onActivityCreated(savedInstanceState);
 
         // Load the preferences from an XML resource
         addPreferencesFromResource(R.xml.preferences);
index 47e47b5..d40cdec 100644 (file)
@@ -1,6 +1,6 @@
 package de.android.mobiads;
 
-import de.android.mobiads.list.MobiAdsListFragment;
+import de.android.mobiads.list.MobiAdsList;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -16,7 +16,6 @@ import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.Bundle;
-import android.widget.Toast;
 
 public class MobiAdsTabsActivity extends Activity {
 
@@ -31,19 +30,19 @@ public class MobiAdsTabsActivity extends Activity {
 
         bar.addTab(bar.newTab()
                 .setText("Local Ads")
-                .setTabListener(new TabListener<MobiAdsListFragment>(
-                        this, "localads", MobiAdsListFragment.class)));
+                .setTabListener(new TabListener<MobiAdsList.MobiAdsListFragment>(
+                        this, "localads", MobiAdsList.MobiAdsListFragment.class)));
         
         if (Cookie.getCookie() != null || isMyServiceRunning()) {
                bar.addTab(bar.newTab()
                     .setText("Control Panel")
-                    .setTabListener(new TabListener<MobiAdsPreferences>(
-                        this, "controlpanel", MobiAdsPreferences.class)));
+                       .setTabListener(new TabListener<MobiAdsPreferences>(
+                                               this, "controlpanel", MobiAdsPreferences.class)));
         }
                
         bar.addTab(bar.newTab()
                        .setText("Login")
-                       .setTabListener(new Login()));
+                               .setTabListener(new Login()));
         
         
         
@@ -63,8 +62,8 @@ public class MobiAdsTabsActivity extends Activity {
        super.onResume();
        if ((Cookie.getCookie() != null) && (getActionBar().getTabCount() == 2)) {
                getActionBar().addTab(getActionBar().newTab()
-                          .setText("Control Panel")
-                          .setTabListener(new TabListener<MobiAdsPreferences>(
+                               .setText("Control Panel")
+                                       .setTabListener(new TabListener<MobiAdsPreferences>(
                                           this, "controlpanel", MobiAdsPreferences.class)), 1);
 
         }
@@ -114,7 +113,7 @@ public class MobiAdsTabsActivity extends Activity {
         }
 
         public void onTabReselected(Tab tab, FragmentTransaction ft) {
-            Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT).show();
+           //Nothing to do here.
         }
     }
     
@@ -134,8 +133,7 @@ public class MobiAdsTabsActivity extends Activity {
 
                @Override
                public void onTabUnselected(Tab tab, FragmentTransaction ft) {
-                       // TODO Auto-generated method stub
-                       
+                       //Nothing to do here            
                }
 
                @Override
diff --git a/Android/MobiAdsTabs/src/de/android/mobiads/list/MobiAdsList.java b/Android/MobiAdsTabs/src/de/android/mobiads/list/MobiAdsList.java
new file mode 100644 (file)
index 0000000..94daec8
--- /dev/null
@@ -0,0 +1,489 @@
+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 android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningServiceInfo;
+import android.app.ListFragment;
+import android.app.LoaderManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.AsyncTaskLoader;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.Loader;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.SearchView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.SearchView.OnQueryTextListener;
+import android.widget.TextView;
+import de.android.mobiads.MobiAdsService;
+import de.android.mobiads.R;
+import de.android.mobiads.provider.Indexer;
+
+public class MobiAdsList extends Activity {
+       
+       /**
+        * A custom Loader that loads all of the installed applications.
+        */
+       public static class AdsListLoader extends AsyncTaskLoader<List<AdsEntry>> {
+               private static final String TAG = "AdsListLoader";
+               List<AdsEntry> 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<AdsEntry> loadInBackground() {
+                       // Create corresponding array of entries and load their labels.
+                       List<AdsEntry> entries = getAdsEntries();
+
+                       return entries;
+               }
+
+               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 = 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.");
+                                                               }
+                                                       }
+                                               }
+                                               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))));                        
+                                               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)));
+                                                       getContext().getContentResolver().update(uriUpdate, values, null, null);
+                                               }
+                                       }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<AdsEntry> 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<AdsEntry> 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<List<AdsEntry>> {
+               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();
+                       
+                       getActivity().registerForContextMenu(listView);
+                       
+                       listView.setOnItemClickListener(new OnItemClickListener() {
+
+                               @Override
+                               public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                                       Uri uri = Uri.parse(mAdapter.getItem(position).getURL());
+                                       startActivity(new Intent(Intent.ACTION_VIEW, uri));
+                               }
+               });
+                       
+                       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);
+
+                       // Prepare the loader.  Either re-connect with an existing one,
+                       // or start a new one.
+                       getLoaderManager().initLoader(0, null, this);
+               }
+
+               @Override
+           public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+               super.onCreateContextMenu(menu, v, menuInfo);
+               MenuInflater inflater = getActivity().getMenuInflater();
+               inflater.inflate(R.menu.menuads, menu);
+           }
+
+               @Override
+           public boolean onContextItemSelected(MenuItem item) {
+               AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+               switch (item.getItemId()) {
+                   case R.id.menuadsremove:
+                       removeAd(info.position);
+                       return true;
+                   default:
+                       return super.onContextItemSelected(item);
+               }
+           }
+               
+               private void removeAd(int position){
+               AdsEntry entry = mAdapter.getItem(position);
+               int idAd = entry.getIdAd();
+               Uri uriDelete = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer" + "/idad/" + idAd);
+               
+               getActivity().getContentResolver().delete(uriDelete, null, null);
+               mAdapter.remove(entry);
+               mAdapter.notifyDataSetChanged();
+           }
+               
+               @Override 
+               public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+                       // Place an action bar item for searching.
+                       MenuItem item = menu.add("Search");
+                       item.setIcon(android.R.drawable.ic_menu_search);
+                       item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+                       SearchView sv = new SearchView(getActivity());
+                       sv.setOnQueryTextListener(this);
+                       item.setActionView(sv);
+               }
+
+               @Override
+               public Loader<List<AdsEntry>> 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<List<AdsEntry>> loader, List<AdsEntry> data) {
+                       mAdapter.setData(data);
+
+                       // The list should now be shown.
+                       if (isResumed()) {
+                               setListShown(true);
+                       } else {
+                               setListShownNoAnimation(true);
+                       }
+
+                       if (isMyServiceRunning()) {
+                               showNotification(0, 0, getText(R.string.remote_service_content_empty_notification));
+                       }
+               }
+
+               @Override
+               public void onLoaderReset(Loader<List<AdsEntry>> loader) {
+                       mAdapter.setData(null);
+               }
+
+               @Override
+               public boolean onQueryTextSubmit(String query) {
+                       // Don't care about this.
+                       return true;
+               }
+
+               @Override
+               public boolean onQueryTextChange(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 boolean isMyServiceRunning() {
+                       ActivityManager manager = (ActivityManager) getActivity().getSystemService(Context.ACTIVITY_SERVICE);
+                       for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
+                               if (MobiAdsService.class.getName().equals(service.service.getClassName())) {
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+               
+               public void showNotification(final int level, final int noReadAds, CharSequence contentText) {        
+                       NotificationManager notificationManager = (NotificationManager)getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
+               
+                       // Set the icon, scrolling text and timestamp
+                       Notification.Builder notificationBuilder = new Notification.Builder(getActivity().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);
+                       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);
+               }
+       }
+       
+       
+       
+
+       public static class AdsEntryAdapter extends ArrayAdapter<AdsEntry> {
+               private final int adsItemLayoutResource;
+
+               public AdsEntryAdapter(final Context context, final int adsItemLayoutResource) {
+                       super(context, 0);
+                       this.adsItemLayoutResource = adsItemLayoutResource;
+               }
+
+               public void setData(List<AdsEntry> data) {
+                       clear();
+                       if (data != null) {
+                               addAll(data);
+                       }
+               }
+
+               /**
+                * Populate new items in the list.
+                */
+               @Override
+               public View getView(final int position, final View convertView, final ViewGroup parent) {
+       
+                       // We need to get the best view (re-used if possible) and then
+                       // retrieve its corresponding ViewHolder, which optimizes lookup efficiency
+                       final View view = getWorkingView(convertView);
+                       final ViewHolder viewHolder = getViewHolder(view);
+                       final AdsEntry entry = getItem(position);
+       
+                       // Setting the text view
+                       viewHolder.titleView.setText(entry.getTitle());
+       
+                       viewHolder.textView.setText(entry.getText());
+       
+                       // Setting image view
+                       viewHolder.imageView.setImageBitmap(entry.getIcon());
+       
+                       return view;
+               }
+
+               private View getWorkingView(final View convertView) {
+                       // The workingView is basically just the convertView re-used if possible
+                       // or inflated new if not possible
+                       View workingView = null;
+       
+                       if(null == convertView) {
+                               final Context context = getContext();
+                               final LayoutInflater inflater = (LayoutInflater)context.getSystemService
+                                               (Context.LAYOUT_INFLATER_SERVICE);
+               
+                               workingView = inflater.inflate(adsItemLayoutResource, null);
+                       } else {
+                               workingView = convertView;
+                       }
+       
+                       return workingView;
+               }
+
+               private ViewHolder getViewHolder(final View workingView) {
+                       // The viewHolder allows us to avoid re-looking up view references
+                       // Since views are recycled, these references will never change
+                       final Object tag = workingView.getTag();
+                       ViewHolder viewHolder = null;
+       
+       
+                       if(null == tag || !(tag instanceof ViewHolder)) {
+                               viewHolder = new ViewHolder();
+               
+                               viewHolder.titleView = (TextView) workingView.findViewById(R.id.ads_entry_title);
+                               viewHolder.textView = (TextView) workingView.findViewById(R.id.ads_entry_text);
+                               viewHolder.imageView = (ImageView) workingView.findViewById(R.id.ads_entry_icon);
+               
+                               workingView.setTag(viewHolder);
+               
+                       } else {
+                               viewHolder = (ViewHolder) tag;
+                       }
+       
+                       return viewHolder;
+               }
+
+               /**
+                * ViewHolder allows us to avoid re-looking up view references
+                * Since views are recycled, these references will never change
+                */
+               private static class ViewHolder {
+                       public TextView titleView;
+                       public TextView textView;
+                       public ImageView imageView;
+               }
+       }
+
+       /**
+        * Encapsulates information about an ads entry
+        */
+       public static class AdsEntry {
+
+               private final String title;
+               private final String text;
+               private final Bitmap icon;
+               private final int idAd;
+               private final String URL;
+
+               public AdsEntry(final String title, final String text, final Bitmap icon, final int idAd, final String URL) {
+                       this.title = title;
+                       this.text = text;
+                       this.icon = icon;
+                       this.idAd = idAd;
+                       this.URL = URL;
+               }
+
+               /**
+                * @return Title of ads entry
+                */
+               public String getTitle() {
+                       return title;
+               }
+
+               /**
+                * @return Text of ads entry
+                */
+               public String getText() {
+                       return text;
+               }
+
+               /**
+                * @return Icon of this ads entry
+                */
+               public Bitmap getIcon() {
+                       return icon;
+               }
+
+               /**
+                * @return Ad unique identifier of this ads entry
+                */
+               public int getIdAd() {
+                       return idAd;
+               }
+
+               /**
+                * @return URL matching this ad.
+                */
+               public String getURL() {
+                       return URL;
+               }
+       }
+}
diff --git a/Android/MobiAdsTabs/src/de/android/mobiads/list/MobiAdsListFragment.java b/Android/MobiAdsTabs/src/de/android/mobiads/list/MobiAdsListFragment.java
deleted file mode 100644 (file)
index 751f85c..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-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 android.app.ActivityManager;
-import android.app.ActivityManager.RunningServiceInfo;
-import android.app.Fragment;
-import android.app.Notification;
-import android.app.NotificationManager;
-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.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ListView;
-import de.android.mobiads.MobiAdsService;
-import de.android.mobiads.R;
-import de.android.mobiads.provider.Indexer;
-
-public class MobiAdsListFragment extends Fragment {
-       private static final String TAG = "MobiAdsListFragment";
-       private AdsEntryAdapter newsEntryAdapter;
-
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-       View v = inflater.inflate(R.layout.mobiadslist, container, false);
-                   
-        // Setup the list view
-        final ListView newsEntryListView = (ListView) v.findViewById(R.id.list);
-        newsEntryAdapter = new AdsEntryAdapter(getActivity(), R.layout.news_entry_list_item);
-        newsEntryListView.setAdapter(newsEntryAdapter);
-        
-        this.registerForContextMenu(newsEntryListView);        
-        
-        newsEntryListView.setOnItemClickListener(new OnItemClickListener() {
-
-                       @Override
-                       public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                               Uri uri = Uri.parse(newsEntryAdapter.getItem(position).getURL());
-                               startActivity(new Intent(Intent.ACTION_VIEW, uri));
-                       }
-        });
-
-       
-        return v;
-    }
-    
-    @Override
-    public void onResume() {
-       // 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... :/
-        // Using FragmentList?
-        for(final AdsEntry entry : getAdsEntries()) {
-               newsEntryAdapter.add(entry);
-        }
-        super.onResume();
-    }
-    
-    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 = getActivity().getContentResolver().query(uri, null, null, null, null);
-       try {
-                       if (cursor.moveToFirst()) {
-                               do {
-                                       values.clear();
-                                       Bitmap bitMap = null;
-                                       FileInputStream file = null;
-                                       try {
-                                               file = getActivity().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_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))));                        
-                                       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)));
-                                               getActivity().getContentResolver().update(uriUpdate, values, null, null);
-                                       }
-                               }while (cursor.moveToNext());
-                       } 
-       }finally {
-                               cursor.close();
-               }
-       
-       if (this.isMyServiceRunning()) {
-               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 = getActivity().getMenuInflater();
-        inflater.inflate(R.menu.menuads, menu);
-    }
-
-    @Override
-    public boolean onContextItemSelected(MenuItem item) {
-        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
-        switch (item.getItemId()) {
-            case R.id.menuadsremove:
-             removeAd(info.position);
-                return true;
-            default:
-                return super.onContextItemSelected(item);
-        }
-    }
-    
-    public void removeAd(int position){
-        AdsEntry entry = this.newsEntryAdapter.getItem(position);
-        int idAd = entry.getIdAd();
-        Uri uriDelete = Uri.parse("content://" + "de.android.mobiads.provider" + "/" + "indexer" + "/idad/" + idAd);
-       
-        getActivity().getContentResolver().delete(uriDelete, null, null);
-        this.newsEntryAdapter.remove(entry);
-        this.newsEntryAdapter.notifyDataSetChanged();    
-    }
-    
-    private boolean isMyServiceRunning() {
-        ActivityManager manager = (ActivityManager) getActivity().getSystemService(Context.ACTIVITY_SERVICE);
-        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
-            if (MobiAdsService.class.getName().equals(service.service.getClassName())) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
-    public void showNotification(final int level, final int noReadAds, CharSequence contentText) {        
-       NotificationManager notificationManager = (NotificationManager)getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
-                
-        // Set the icon, scrolling text and timestamp
-        Notification.Builder notificationBuilder = new Notification.Builder(getActivity().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);
-        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 936278c..7a1239b 100644 (file)
@@ -37,7 +37,7 @@ public class MobiAdsNewAdsActivity extends Activity {
                
                // Setup the list view
                final ListView newsEntryListView = (ListView) findViewById(R.id.list);
-               final AdsEntryAdapter newsEntryAdapter = new AdsEntryAdapter(this, R.layout.news_entry_list_item);
+               final AdsEntryAdapter newsEntryAdapter = new AdsEntryAdapter(this, R.layout.ads_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...