org.adblockplus.android.configurators.ManualProxyConfigurator.java Source code

Java tutorial

Introduction

Here is the source code for org.adblockplus.android.configurators.ManualProxyConfigurator.java

Source

/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-2016 Eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.adblockplus.android.configurators;

import java.net.InetAddress;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;

import org.adblockplus.android.ConfigurationActivity;
import org.adblockplus.android.ProxyService;
import org.adblockplus.android.R;
import org.adblockplus.android.compat.ProxyProperties;
import org.adblockplus.brazil.RequestHandler;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.support.v4.app.NotificationCompat;

/**
 * A dummy registrator only holding callbacks and checks.
 */
public class ManualProxyConfigurator implements ProxyConfigurator {
    final Context context;
    private ProxyProperties proxyProperties = null;
    private static final int NOTRAFFIC_NOTIFICATION_ID = R.string.proxysettings_name;
    private static final int NO_TRAFFIC_TIMEOUT = 5 * 60 * 1000; // 5 minutes
    private volatile boolean isRegistered = false;
    private NoTrafficWorker noTrafficWorker = null;
    private final ReentrantLock noTrafficAccessLock = new ReentrantLock();
    private final Handler uiHandler;

    public ManualProxyConfigurator(final Context context) {
        this.uiHandler = new Handler();
        this.context = context;
    }

    @Override
    public boolean initialize() {
        return true;
    }

    @Override
    public boolean registerProxy(final InetAddress address, final int port) {
        this.proxyProperties = new ProxyProperties(address.getHostName(), port, "");
        this.startNoTrafficCheck();
        return true;
    }

    @Override
    public void unregisterProxy() {
        this.isRegistered = false;
        this.abortNoTrafficCheck();
    }

    @Override
    public void shutdown() {
        this.removeErrorNotification();
    }

    @Override
    public ProxyRegistrationType getType() {
        return ProxyRegistrationType.MANUAL;
    }

    @Override
    public boolean isRegistered() {
        return this.isRegistered;
    }

    @Override
    public boolean isSticky() {
        return true;
    }

    @Override
    public String toString() {
        return "[ProxyConfigurator: " + this.getType() + "]";
    }

    private void removeErrorNotification() {
        final NotificationManager notificationManager = (NotificationManager) this.context
                .getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.cancel(NOTRAFFIC_NOTIFICATION_ID);
    }

    private void startNoTrafficCheck() {
        this.noTrafficAccessLock.lock();
        try {
            if (this.noTrafficWorker == null) {
                this.noTrafficWorker = new NoTrafficWorker(this);
                final Thread t = new Thread(this.noTrafficWorker);
                t.setDaemon(true);
                t.start();
            }
        } finally {
            this.noTrafficAccessLock.unlock();
        }
    }

    private void abortNoTrafficCheck() {
        this.noTrafficAccessLock.lock();
        try {
            if (this.noTrafficWorker != null) {
                this.noTrafficWorker.stop();
            }
        } finally {
            this.noTrafficWorker = null;
            this.noTrafficAccessLock.unlock();
        }
    }

    private synchronized void trafficReceived() {
        this.isRegistered = true;
        this.abortNoTrafficCheck();

        this.uiHandler.post(new Runnable() {
            @Override
            public void run() {
                ManualProxyConfigurator.this.removeErrorNotification();
                ManualProxyConfigurator.this.context
                        .sendBroadcast(new Intent(ProxyService.PROXY_STATE_CHANGED_ACTION));
            }
        });
    }

    private synchronized void noTrafficReceived() {
        this.isRegistered = false;
        this.abortNoTrafficCheck();

        this.uiHandler.post(new Runnable() {
            @Override
            public void run() {
                final Context context = ManualProxyConfigurator.this.context;
                // Show warning notification
                final Intent intent = new Intent(context, ConfigurationActivity.class)
                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        .putExtra("port", ManualProxyConfigurator.this.proxyProperties.getPort());

                final PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent,
                        PendingIntent.FLAG_UPDATE_CURRENT);

                final NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                        .setSmallIcon(R.drawable.ic_stat_warning).setWhen(System.currentTimeMillis())
                        .setAutoCancel(true).setContentIntent(contentIntent)
                        .setContentTitle(context.getText(R.string.app_name))
                        .setContentText(context.getText(R.string.notif_notraffic));

                final NotificationManager notificationManager = (NotificationManager) context
                        .getSystemService(Context.NOTIFICATION_SERVICE);
                notificationManager.notify(NOTRAFFIC_NOTIFICATION_ID, builder.getNotification());

                context.sendBroadcast(new Intent(ProxyService.PROXY_STATE_CHANGED_ACTION));
            }
        });
    }

    private static class NoTrafficWorker implements Runnable {
        private volatile boolean running = true;
        private final Semaphore finished = new Semaphore(1);
        private final ManualProxyConfigurator manualProxyConfigurator;

        public NoTrafficWorker(final ManualProxyConfigurator manualProxyConfigurator) {
            this.manualProxyConfigurator = manualProxyConfigurator;
            this.finished.acquireUninterruptibly();
        }

        @Override
        public void run() {
            try {
                final long endTime = System.currentTimeMillis() + NO_TRAFFIC_TIMEOUT;

                final long blockedStart = RequestHandler.getBlockedRequestCount();
                final long unblockedStart = RequestHandler.getUnblockedRequestCount();

                while (this.running) {
                    try {
                        if (System.currentTimeMillis() >= endTime) {
                            this.running = false;
                            this.manualProxyConfigurator.noTrafficReceived();
                            break;
                        }

                        if (RequestHandler.getBlockedRequestCount() != blockedStart
                                || RequestHandler.getUnblockedRequestCount() != unblockedStart) {
                            this.running = false;
                            this.manualProxyConfigurator.trafficReceived();
                            break;
                        }

                        Thread.sleep(100);
                    } catch (final Throwable t) {
                        // Swallow everything to keep this thread alive at all cost
                    }
                }
            } finally {
                this.finished.release();
            }
        }

        public synchronized void stop() {
            if (this.running) {
                this.running = false;
                this.finished.acquireUninterruptibly();
            }
        }
    }
}