2 * Copyright (C) 2009 Felix Bechstein
4 * This file is part of AdBlock.
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
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
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
;
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
;
56 * Main Activity to control ad blocking Proxy.
58 * @author Felix Bechstein
60 public class AdBlock
extends Activity
implements OnClickListener
,
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;
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;
86 private SharedPreferences preferences
;
87 /** Prefs. import URL. */
88 private String importUrl
= null;
91 private ArrayList
<String
> filter
= new ArrayList
<String
>();
92 /** The ArrayAdapter. */
93 private ArrayAdapter
<String
> adapter
= null;
96 private int itemToEdit
= -1;
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
= "";
114 protected final Boolean
doInBackground(final String
... dummy
) {
116 HttpURLConnection c
= (HttpURLConnection
) (new URL(
117 AdBlock
.this.importUrl
)).openConnection();
118 int resp
= c
.getResponseCode();
122 BufferedReader reader
= new BufferedReader(
123 new InputStreamReader(c
.getInputStream()));
124 AdBlock
.this.filter
.clear();
126 String s
= reader
.readLine();
129 } else if (s
.length() > 0) {
130 AdBlock
.this.filter
.add(s
);
135 } catch (MalformedURLException e
) {
136 Log
.e(AdBlock
.this.TAG
, null, e
);
137 this.message
= e
.toString();
139 } catch (IOException e
) {
140 this.message
= e
.toString();
141 Log
.e(AdBlock
.this.TAG
, null, e
);
147 * Merge imported filter to the real one.
153 protected final void onPostExecute(final Boolean result
) {
154 if (result
.booleanValue()) {
155 Toast
.makeText(AdBlock
.this, "imported", Toast
.LENGTH_LONG
)
157 AdBlock
.this.adapter
.notifyDataSetChanged();
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
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
);
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) {
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
222 editor
.putString(Proxy
.PREFS_FILTER
, sb
.toString());
223 editor
.putString(PREFS_IMPORT_URL
, this.importUrl
);
227 /** Called on pause. */
229 public final void onPause() {
231 this.savePreferences();
241 public final void onClick(final View v
) {
243 case R
.id
.start_service
:
244 this.savePreferences();
245 this.startService(new Intent(this, Proxy
.class));
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;
259 this.adapter
.notifyDataSetChanged();
263 this.dismissDialog(DIALOG_IMPORT
);
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);
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
));
288 public final boolean onCreateOptionsMenu(final Menu menu
) {
289 MenuInflater inflater
= this.getMenuInflater();
290 inflater
.inflate(R
.menu
.menu
, menu
);
295 * Handles item selections.
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
);
306 case R
.id
.item_import
:
307 this.showDialog(DIALOG_IMPORT
);
309 // case R.id.item_export:
311 // // OutputStream os = this.openFileOutput(FILENAME_EXPORT,
312 // // MODE_WORLD_READABLE);
313 // File file = new File(FILENAME_EXPORT);
314 // if (!file.createNewFile()) {
316 // file.createNewFile();
318 // OutputStream os = new FileOutputStream(file);
319 // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
321 // for (String s : this.filter) {
322 // if (s.indexOf("admob") < 0) { // won't block admob
323 // bw.append(s + "\n");
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();
341 * Called to create dialog.
348 protected final Dialog
onCreateDialog(final int id
) {
352 myDialog
= new Dialog(this);
353 myDialog
.setContentView(R
.layout
.about
);
354 myDialog
.setTitle(this.getResources().getString(R
.string
.about_
)
356 + this.getResources().getString(R
.string
.app_version
));
357 ((Button
) myDialog
.findViewById(R
.id
.btn_donate
))
358 .setOnClickListener(this);
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);
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
);
376 String
[] changes
= this.getResources().getStringArray(
378 for (String c
: changes
) {
379 tw
= new TextView(this);
391 * Provides an opportunity to prepare a managed dialog before it is being
395 * The id of the managed dialog.
400 protected final void onPrepareDialog(final int id
, final Dialog dialog
) {
401 super.onPrepareDialog(id
, dialog
);
404 ((EditText
) dialog
.findViewById(R
.id
.import_url
))
405 .setText(this.importUrl
);
413 * Handle clicked ListItem.
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);
430 this.getResources().getStringArray(R
.array
.itemDialog
),
431 new DialogInterface
.OnClickListener() {
432 public void onClick(final DialogInterface dialog
,
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
442 case ITEM_DIALOG_DELETE
:
443 AdBlock
.this.filter
.remove(position
);
444 AdBlock
.this.adapter
.notifyDataSetChanged();
451 AlertDialog alert
= builder
.create();