-private to inner classes
[adBlock.git] / src / de / ub0r / android / adBlock / AdBlock.java
bloba82db403664ea7e8148e05b6d67355b205aad099
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.ActivityNotFoundException;
33 import android.content.DialogInterface;
34 import android.content.Intent;
35 import android.content.SharedPreferences;
36 import android.net.Uri;
37 import android.os.AsyncTask;
38 import android.os.Bundle;
39 import android.preference.PreferenceManager;
40 import android.util.Log;
41 import android.view.Menu;
42 import android.view.MenuInflater;
43 import android.view.MenuItem;
44 import android.view.View;
45 import android.view.View.OnClickListener;
46 import android.widget.AdapterView;
47 import android.widget.ArrayAdapter;
48 import android.widget.Button;
49 import android.widget.EditText;
50 import android.widget.LinearLayout;
51 import android.widget.ListView;
52 import android.widget.TextView;
53 import android.widget.Toast;
54 import android.widget.AdapterView.OnItemClickListener;
56 /**
57 * Main Activity to control ad blocking Proxy.
59 * @author Felix Bechstein
61 public class AdBlock extends Activity implements OnClickListener,
62 OnItemClickListener {
64 /** Tag for output. */
65 private static final String TAG = "AdBlock";
67 /** Prefs: name for last version run. */
68 private static final String PREFS_LAST_RUN = "lastrun";
69 /** Preferences: import url. */
70 private static final String PREFS_IMPORT_URL = "importurl";
72 /** Filename for export of filter. */
73 // private static final String FILENAME_EXPORT = "/sdcard/filter.txt";
74 /** ItemDialog: edit. */
75 private static final short ITEM_DIALOG_EDIT = 0;
76 /** ItemDialog: delete. */
77 private static final short ITEM_DIALOG_DELETE = 1;
79 /** Dialog: about. */
80 private static final int DIALOG_ABOUT = 0;
81 /** Dialog: import. */
82 private static final int DIALOG_IMPORT = 1;
83 /** Dialog: update. */
84 private static final int DIALOG_UPDATE = 2;
86 /** Prefs. */
87 private SharedPreferences preferences;
88 /** Prefs. import URL. */
89 private String importUrl = null;
91 /** The filter. */
92 private ArrayList<String> filter = new ArrayList<String>();
93 /** The ArrayAdapter. */
94 private ArrayAdapter<String> adapter = null;
96 /** Editmode? */
97 private int itemToEdit = -1;
99 /**
100 * Import filter from URL on background.
102 * @author Felix Bechstein
104 class Importer extends AsyncTask<String, Boolean, Boolean> {
105 /** Error message. */
106 private String message = "";
109 * Do the work.
111 * @param dummy
112 * nothing here
113 * @return successful?
115 @Override
116 protected final Boolean doInBackground(final String... dummy) {
117 try {
118 HttpURLConnection c = (HttpURLConnection) (new URL(
119 AdBlock.this.importUrl)).openConnection();
120 int resp = c.getResponseCode();
121 if (resp != 200) {
122 return false;
124 BufferedReader reader = new BufferedReader(
125 new InputStreamReader(c.getInputStream()));
126 AdBlock.this.filter.clear();
127 while (true) {
128 String s = reader.readLine();
129 if (s == null) {
130 break;
131 } else if (s.length() > 0) {
132 AdBlock.this.filter.add(s);
135 reader.close();
136 return true;
137 } catch (MalformedURLException e) {
138 Log.e(AdBlock.TAG, null, e);
139 this.message = e.toString();
140 return false;
141 } catch (IOException e) {
142 this.message = e.toString();
143 Log.e(AdBlock.TAG, null, e);
144 return false;
149 * Merge imported filter to the real one.
151 * @param result
152 * nothing here
154 @Override
155 protected final void onPostExecute(final Boolean result) {
156 if (result.booleanValue()) {
157 Toast.makeText(AdBlock.this, "imported", Toast.LENGTH_LONG)
158 .show();
159 AdBlock.this.adapter.notifyDataSetChanged();
160 } else {
161 Toast.makeText(AdBlock.this, "failed: " + this.message,
162 Toast.LENGTH_LONG).show();
168 * {@inheritDoc}
170 @Override
171 public final void onCreate(final Bundle savedInstanceState) {
172 super.onCreate(savedInstanceState);
173 this.setContentView(R.layout.main);
175 this.preferences = PreferenceManager.getDefaultSharedPreferences(this);
176 // display changelog?
177 String v0 = this.preferences.getString(PREFS_LAST_RUN, "");
178 String v1 = this.getString(R.string.app_version);
179 if (!v0.equals(v1)) {
180 SharedPreferences.Editor editor = this.preferences.edit();
181 editor.putString(PREFS_LAST_RUN, v1);
182 editor.commit();
183 this.showDialog(DIALOG_UPDATE);
186 ((EditText) this.findViewById(R.id.port)).setText(this.preferences
187 .getString(Proxy.PREFS_PORT, "8080"));
188 String f = this.preferences.getString(Proxy.PREFS_FILTER, this
189 .getString(R.string.default_filter));
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);
209 this.startService(new Intent(this, Proxy.class));
212 /** Save Preferences. */
213 private void savePreferences() {
214 SharedPreferences.Editor editor = this.preferences.edit();
215 editor.putString(Proxy.PREFS_PORT, ((EditText) this
216 .findViewById(R.id.port)).getText().toString());
217 StringBuilder sb = new StringBuilder();
218 for (String s : this.filter) {
219 if (s.indexOf("admob") < 0 // won't block admob
220 && s.indexOf("google") < 0) { // won't block google
221 sb.append(s + "\n");
224 editor.putString(Proxy.PREFS_FILTER, sb.toString());
225 editor.putString(PREFS_IMPORT_URL, this.importUrl);
226 editor.commit();
230 * {@inheritDoc}
232 @Override
233 public final void onPause() {
234 super.onPause();
235 this.savePreferences();
239 * {@inheritDoc}
241 @Override
242 public final void onClick(final View v) {
243 switch (v.getId()) {
244 case R.id.start_service:
245 this.savePreferences();
246 this.startService(new Intent(this, Proxy.class));
247 break;
248 case R.id.stop_service:
249 this.stopService(new Intent(this, Proxy.class));
250 case R.id.filter_add_:
251 EditText et = (EditText) this.findViewById(R.id.filter_add);
252 String f = et.getText().toString();
253 if (f.length() > 0) {
254 if (this.itemToEdit >= 0) {
255 this.filter.remove(this.itemToEdit);
256 this.itemToEdit = -1;
258 this.filter.add(f);
259 et.setText("");
260 this.adapter.notifyDataSetChanged();
262 break;
263 case R.id.cancel:
264 this.dismissDialog(DIALOG_IMPORT);
265 break;
266 case R.id.ok:
267 this.dismissDialog(DIALOG_IMPORT);
268 this.importUrl = ((EditText) v.getRootView().findViewById(
269 R.id.import_url)).getText().toString();
270 new Importer().execute((String[]) null);
271 break;
272 default:
273 break;
278 * {@inheritDoc}
280 @Override
281 public final boolean onCreateOptionsMenu(final Menu menu) {
282 MenuInflater inflater = this.getMenuInflater();
283 inflater.inflate(R.menu.menu, menu);
284 return true;
288 * {@inheritDoc}
290 public final boolean onOptionsItemSelected(final MenuItem item) {
291 switch (item.getItemId()) {
292 case R.id.item_about: // start about dialog
293 this.showDialog(DIALOG_ABOUT);
294 return true;
295 case R.id.item_import:
296 this.showDialog(DIALOG_IMPORT);
297 return true;
298 case R.id.item_donate:
299 try {
300 this.startActivity(new Intent(Intent.ACTION_VIEW, Uri
301 .parse(this.getString(R.string.donate_url))));
302 } catch (ActivityNotFoundException e) {
303 Log.e(TAG, "no browser", e);
305 return true;
306 case R.id.item_more:
307 try {
308 this.startActivity(new Intent(Intent.ACTION_VIEW, Uri
309 .parse("market://search?q=pub:\"Felix Bechstein\"")));
310 } catch (ActivityNotFoundException e) {
311 Log.e(TAG, "no market", e);
313 return true;
314 // case R.id.item_export:
315 // try {
316 // // OutputStream os = this.openFileOutput(FILENAME_EXPORT,
317 // // MODE_WORLD_READABLE);
318 // File file = new File(FILENAME_EXPORT);
319 // if (!file.createNewFile()) {
320 // file.delete();
321 // file.createNewFile();
322 // }
323 // OutputStream os = new FileOutputStream(file);
324 // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
325 // os));
326 // for (String s : this.filter) {
327 // if (s.indexOf("admob") < 0) { // won't block admob
328 // bw.append(s + "\n");
329 // }
330 // }
331 // bw.close();
332 // os.close();
333 // Toast.makeText(this, "exported to " + FILENAME_EXPORT,
334 // Toast.LENGTH_LONG).show();
335 // } catch (IOException e) {
336 // Log.e(this.TAG, null, e);
337 // Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
338 // }
339 // return true;
340 default:
341 return false;
346 * {@inheritDoc}
348 @Override
349 protected final Dialog onCreateDialog(final int id) {
350 Dialog d;
351 switch (id) {
352 case DIALOG_ABOUT:
353 d = new Dialog(this);
354 d.setContentView(R.layout.about);
355 d.setTitle(this.getString(R.string.about_) + " v"
356 + this.getString(R.string.app_version));
357 return d;
358 case DIALOG_IMPORT:
359 d = new Dialog(this);
360 d.setContentView(R.layout.import_url);
361 d.setTitle(this.getString(R.string.import_url_));
362 ((Button) d.findViewById(R.id.ok)).setOnClickListener(this);
363 ((Button) d.findViewById(R.id.cancel)).setOnClickListener(this);
364 return d;
365 case DIALOG_UPDATE:
366 final AlertDialog.Builder builder = new AlertDialog.Builder(this);
367 builder.setTitle(R.string.changelog_);
368 final String[] changes = this.getResources().getStringArray(
369 R.array.updates);
370 final StringBuilder buf = new StringBuilder(changes[0]);
371 for (int i = 1; i < changes.length; i++) {
372 buf.append("\n\n");
373 buf.append(changes[i]);
375 builder.setIcon(android.R.drawable.ic_menu_info_details);
376 builder.setMessage(buf.toString());
377 builder.setCancelable(true);
378 builder.setPositiveButton(android.R.string.ok,
379 new DialogInterface.OnClickListener() {
380 public void onClick(final DialogInterface dialog,
381 final int id) {
382 dialog.cancel();
385 return builder.create();
386 default:
387 return null;
392 * {@inheritDoc}
394 @Override
395 protected final void onPrepareDialog(final int id, final Dialog dialog) {
396 super.onPrepareDialog(id, dialog);
397 switch (id) {
398 case DIALOG_IMPORT:
399 ((EditText) dialog.findViewById(R.id.import_url))
400 .setText(this.importUrl);
401 break;
402 default:
403 break;
408 * {@inheritDoc}
410 @Override
411 public final void onItemClick(final AdapterView<?> parent, final View v,
412 final int position, final long id) {
414 AlertDialog.Builder builder = new AlertDialog.Builder(this);
415 builder.setItems(
416 this.getResources().getStringArray(R.array.itemDialog),
417 new DialogInterface.OnClickListener() {
418 public void onClick(final DialogInterface dialog,
419 final int item) {
420 switch (item) {
421 case ITEM_DIALOG_EDIT:
422 AdBlock.this.itemToEdit = position;
423 ((EditText) AdBlock.this
424 .findViewById(R.id.filter_add))
425 .setText(AdBlock.this.adapter
426 .getItem(position));
427 break;
428 case ITEM_DIALOG_DELETE:
429 AdBlock.this.filter.remove(position);
430 AdBlock.this.adapter.notifyDataSetChanged();
431 break;
432 default:
433 break;
437 AlertDialog alert = builder.create();
438 alert.show();