decrease mem impact
[adBlock.git] / src / de / ub0r / android / adBlock / AdBlock.java
blob2b26951afd7d91100908c7dbc3913242a98567e2
1 /*
2 * Copyright (C) 2009 Felix Bechstein
3 *
4 * This file is part of AdBlock.
5 *
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free Software
8 * Foundation; either version 3 of the License, or (at your option) any later
9 * version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
16 * You should have received a copy of the GNU General Public License along with
17 * this program; If not, see <http://www.gnu.org/licenses/>.
19 package de.ub0r.android.adBlock;
21 import java.io.BufferedReader;
22 import java.io.IOException;
23 import java.io.InputStreamReader;
24 import java.net.HttpURLConnection;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.util.ArrayList;
29 import android.app.Activity;
30 import android.app.AlertDialog;
31 import android.app.Dialog;
32 import android.content.DialogInterface;
33 import android.content.Intent;
34 import android.content.SharedPreferences;
35 import android.net.Uri;
36 import android.os.AsyncTask;
37 import android.os.Bundle;
38 import android.preference.PreferenceManager;
39 import android.util.Log;
40 import android.view.Menu;
41 import android.view.MenuInflater;
42 import android.view.MenuItem;
43 import android.view.View;
44 import android.view.View.OnClickListener;
45 import android.widget.AdapterView;
46 import android.widget.ArrayAdapter;
47 import android.widget.Button;
48 import android.widget.EditText;
49 import android.widget.LinearLayout;
50 import android.widget.ListView;
51 import android.widget.TextView;
52 import android.widget.Toast;
53 import android.widget.AdapterView.OnItemClickListener;
55 /**
56 * Main Activity to control ad blocking Proxy.
58 * @author Felix Bechstein
60 public class AdBlock extends Activity implements OnClickListener,
61 OnItemClickListener {
63 /** Tag for output. */
64 private static final String TAG = "AdBlock";
66 /** Prefs: name for last version run */
67 private static final String PREFS_LAST_RUN = "lastrun";
68 /** Preferences: import url. */
69 private static final String PREFS_IMPORT_URL = "importurl";
71 /** Filename for export of filter. */
72 // private static final String FILENAME_EXPORT = "/sdcard/filter.txt";
73 /** ItemDialog: edit. */
74 private static final short ITEM_DIALOG_EDIT = 0;
75 /** ItemDialog: delete. */
76 private static final short ITEM_DIALOG_DELETE = 1;
78 /** Dialog: about. */
79 private static final int DIALOG_ABOUT = 0;
80 /** Dialog: import. */
81 private static final int DIALOG_IMPORT = 1;
82 /** Dialog: update. */
83 private static final int DIALOG_UPDATE = 2;
85 /** Prefs. */
86 private SharedPreferences preferences;
87 /** Prefs. import URL. */
88 private String importUrl = null;
90 /** The filter. */
91 private ArrayList<String> filter = new ArrayList<String>();
92 /** The ArrayAdapter. */
93 private ArrayAdapter<String> adapter = null;
95 /** Editmode? */
96 private int itemToEdit = -1;
98 /**
99 * Import filter from URL on background.
101 * @author Felix Bechstein
103 private class Importer extends AsyncTask<String, Boolean, Boolean> {
104 /** Error message. */
105 private String message = "";
108 * Do the work.
110 * @param dummy
111 * nothing here
113 @Override
114 protected final Boolean doInBackground(final String... dummy) {
115 try {
116 HttpURLConnection c = (HttpURLConnection) (new URL(
117 AdBlock.this.importUrl)).openConnection();
118 int resp = c.getResponseCode();
119 if (resp != 200) {
120 return false;
122 BufferedReader reader = new BufferedReader(
123 new InputStreamReader(c.getInputStream()));
124 AdBlock.this.filter.clear();
125 while (true) {
126 String s = reader.readLine();
127 if (s == null) {
128 break;
129 } else if (s.length() > 0) {
130 AdBlock.this.filter.add(s);
133 reader.close();
134 return true;
135 } catch (MalformedURLException e) {
136 Log.e(AdBlock.this.TAG, null, e);
137 this.message = e.toString();
138 return false;
139 } catch (IOException e) {
140 this.message = e.toString();
141 Log.e(AdBlock.this.TAG, null, e);
142 return false;
147 * Merge imported filter to the real one.
149 * @param result
150 * nothing here
152 @Override
153 protected final void onPostExecute(final Boolean result) {
154 if (result.booleanValue()) {
155 Toast.makeText(AdBlock.this, "imported", Toast.LENGTH_LONG)
156 .show();
157 AdBlock.this.adapter.notifyDataSetChanged();
158 } else {
159 Toast.makeText(AdBlock.this, "failed: " + this.message,
160 Toast.LENGTH_LONG).show();
166 * Called when the activity is first created.
168 * @param savedInstanceState
169 * saved InstanceState
171 @Override
172 public final void onCreate(final Bundle savedInstanceState) {
173 super.onCreate(savedInstanceState);
174 this.setContentView(R.layout.main);
176 this.preferences = PreferenceManager.getDefaultSharedPreferences(this);
177 // display changelog?
178 String v0 = this.preferences.getString(PREFS_LAST_RUN, "");
179 String v1 = this.getResources().getString(R.string.app_version);
180 if (!v0.equals(v1)) {
181 SharedPreferences.Editor editor = this.preferences.edit();
182 editor.putString(PREFS_LAST_RUN, v1);
183 editor.commit();
184 this.showDialog(DIALOG_UPDATE);
187 ((EditText) this.findViewById(R.id.port)).setText(this.preferences
188 .getString(Proxy.PREFS_PORT, "8080"));
189 String f = this.preferences.getString(Proxy.PREFS_FILTER, "/ads/\n.ads/");
190 for (String s : f.split("\n")) {
191 if (s.length() > 0) {
192 this.filter.add(s);
195 this.importUrl = this.preferences.getString(PREFS_IMPORT_URL, "");
197 ((Button) this.findViewById(R.id.start_service))
198 .setOnClickListener(this);
199 ((Button) this.findViewById(R.id.stop_service))
200 .setOnClickListener(this);
201 ((Button) this.findViewById(R.id.filter_add_)).setOnClickListener(this);
202 ListView lv = (ListView) this.findViewById(R.id.filter);
203 this.adapter = new ArrayAdapter<String>(this,
204 R.layout.simple_list_item_1, this.filter);
205 lv.setAdapter(this.adapter);
206 lv.setTextFilterEnabled(true);
207 lv.setOnItemClickListener(this);
210 /** Save Preferences. */
211 private void savePreferences() {
212 SharedPreferences.Editor editor = this.preferences.edit();
213 editor.putString(Proxy.PREFS_PORT, ((EditText) this.findViewById(R.id.port))
214 .getText().toString());
215 StringBuilder sb = new StringBuilder();
216 for (String s : this.filter) {
217 if (s.indexOf("admob") < 0 // won't block admob
218 && s.indexOf("google") < 0) { // won't block google
219 sb.append(s + "\n");
222 editor.putString(Proxy.PREFS_FILTER, sb.toString());
223 editor.putString(PREFS_IMPORT_URL, this.importUrl);
224 editor.commit();
227 /** Called on pause. */
228 @Override
229 public final void onPause() {
230 super.onPause();
231 this.savePreferences();
235 * OnClickListener.
237 * @param v
238 * view
240 @Override
241 public final void onClick(final View v) {
242 switch (v.getId()) {
243 case R.id.start_service:
244 this.savePreferences();
245 this.startService(new Intent(this, Proxy.class));
246 break;
247 case R.id.stop_service:
248 this.stopService(new Intent(this, Proxy.class));
249 case R.id.filter_add_:
250 EditText et = (EditText) this.findViewById(R.id.filter_add);
251 String f = et.getText().toString();
252 if (f.length() > 0) {
253 if (this.itemToEdit >= 0) {
254 this.filter.remove(this.itemToEdit);
255 this.itemToEdit = -1;
257 this.filter.add(f);
258 et.setText("");
259 this.adapter.notifyDataSetChanged();
261 break;
262 case R.id.cancel:
263 this.dismissDialog(DIALOG_IMPORT);
264 break;
265 case R.id.ok:
266 this.dismissDialog(DIALOG_IMPORT);
267 this.importUrl = ((EditText) v.getRootView().findViewById(
268 R.id.import_url)).getText().toString();
269 new Importer().execute((String[]) null);
270 break;
271 case R.id.btn_donate:
272 Uri uri = Uri.parse(this.getString(R.string.donate_url));
273 this.startActivity(new Intent(Intent.ACTION_VIEW, uri));
274 break;
275 default:
276 break;
281 * Create menu.
283 * @param menu
284 * menu to inflate
285 * @return ok/fail?
287 @Override
288 public final boolean onCreateOptionsMenu(final Menu menu) {
289 MenuInflater inflater = this.getMenuInflater();
290 inflater.inflate(R.menu.menu, menu);
291 return true;
295 * Handles item selections.
297 * @param item
298 * menu item
299 * @return done?
301 public final boolean onOptionsItemSelected(final MenuItem item) {
302 switch (item.getItemId()) {
303 case R.id.item_about: // start about dialog
304 this.showDialog(DIALOG_ABOUT);
305 return true;
306 case R.id.item_import:
307 this.showDialog(DIALOG_IMPORT);
308 return true;
309 // case R.id.item_export:
310 // try {
311 // // OutputStream os = this.openFileOutput(FILENAME_EXPORT,
312 // // MODE_WORLD_READABLE);
313 // File file = new File(FILENAME_EXPORT);
314 // if (!file.createNewFile()) {
315 // file.delete();
316 // file.createNewFile();
317 // }
318 // OutputStream os = new FileOutputStream(file);
319 // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
320 // os));
321 // for (String s : this.filter) {
322 // if (s.indexOf("admob") < 0) { // won't block admob
323 // bw.append(s + "\n");
324 // }
325 // }
326 // bw.close();
327 // os.close();
328 // Toast.makeText(this, "exported to " + FILENAME_EXPORT,
329 // Toast.LENGTH_LONG).show();
330 // } catch (IOException e) {
331 // Log.e(this.TAG, null, e);
332 // Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
333 // }
334 // return true;
335 default:
336 return false;
341 * Called to create dialog.
343 * @param id
344 * Dialog id
345 * @return dialog
347 @Override
348 protected final Dialog onCreateDialog(final int id) {
349 Dialog myDialog;
350 switch (id) {
351 case DIALOG_ABOUT:
352 myDialog = new Dialog(this);
353 myDialog.setContentView(R.layout.about);
354 myDialog.setTitle(this.getResources().getString(R.string.about_)
355 + " v"
356 + this.getResources().getString(R.string.app_version));
357 ((Button) myDialog.findViewById(R.id.btn_donate))
358 .setOnClickListener(this);
359 break;
360 case DIALOG_IMPORT:
361 myDialog = new Dialog(this);
362 myDialog.setContentView(R.layout.import_url);
363 myDialog.setTitle(this.getResources().getString(
364 R.string.import_url_));
365 ((Button) myDialog.findViewById(R.id.ok)).setOnClickListener(this);
366 ((Button) myDialog.findViewById(R.id.cancel))
367 .setOnClickListener(this);
368 break;
369 case DIALOG_UPDATE:
370 myDialog = new Dialog(this);
371 myDialog.setContentView(R.layout.update);
372 myDialog.setTitle(R.string.changelog_);
373 LinearLayout layout = (LinearLayout) myDialog
374 .findViewById(R.id.base_view);
375 TextView tw;
376 String[] changes = this.getResources().getStringArray(
377 R.array.updates);
378 for (String c : changes) {
379 tw = new TextView(this);
380 tw.setText(c);
381 layout.addView(tw);
383 break;
384 default:
385 myDialog = null;
387 return myDialog;
391 * Provides an opportunity to prepare a managed dialog before it is being
392 * shown.
394 * @param id
395 * The id of the managed dialog.
396 * @param dialog
397 * The dialog.
399 @Override
400 protected final void onPrepareDialog(final int id, final Dialog dialog) {
401 super.onPrepareDialog(id, dialog);
402 switch (id) {
403 case DIALOG_IMPORT:
404 ((EditText) dialog.findViewById(R.id.import_url))
405 .setText(this.importUrl);
406 break;
407 default:
408 break;
413 * Handle clicked ListItem.
415 * @param parent
416 * parent AdapterView
417 * @param v
418 * View
419 * @param position
420 * Position
421 * @param id
422 * id
424 @Override
425 public final void onItemClick(final AdapterView<?> parent, final View v,
426 final int position, final long id) {
428 AlertDialog.Builder builder = new AlertDialog.Builder(this);
429 builder.setItems(
430 this.getResources().getStringArray(R.array.itemDialog),
431 new DialogInterface.OnClickListener() {
432 public void onClick(final DialogInterface dialog,
433 final int item) {
434 switch (item) {
435 case ITEM_DIALOG_EDIT:
436 AdBlock.this.itemToEdit = position;
437 ((EditText) AdBlock.this
438 .findViewById(R.id.filter_add))
439 .setText(AdBlock.this.adapter
440 .getItem(position));
441 break;
442 case ITEM_DIALOG_DELETE:
443 AdBlock.this.filter.remove(position);
444 AdBlock.this.adapter.notifyDataSetChanged();
445 break;
446 default:
447 break;
451 AlertDialog alert = builder.create();
452 alert.show();