Out with the old; in with the new

Switch to the official "JobScheduler" etc naming.

Bug 14997851

Change-Id: I73a61aaa9af0740c114d08188bd97c52f3ac86b7
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
new file mode 100644
index 0000000..7e79ff7
--- /dev/null
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2014 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 com.android.server.job.controllers;
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.server.ConnectivityService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
+
+import java.io.PrintWriter;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Handles changes in connectivity.
+ * We are only interested in metered vs. unmetered networks, and we're interested in them on a
+ * per-user basis.
+ */
+public class ConnectivityController extends StateController implements
+        ConnectivityManager.OnNetworkActiveListener {
+    private static final String TAG = "JobScheduler.Conn";
+
+    private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
+    private final BroadcastReceiver mConnectivityChangedReceiver =
+            new ConnectivityChangedReceiver();
+    /** Singleton. */
+    private static ConnectivityController mSingleton;
+    private static Object sCreationLock = new Object();
+    /** Track whether the latest active network is metered. */
+    private boolean mNetworkUnmetered;
+    /** Track whether the latest active network is connected. */
+    private boolean mNetworkConnected;
+
+    public static ConnectivityController get(JobSchedulerService jms) {
+        synchronized (sCreationLock) {
+            if (mSingleton == null) {
+                mSingleton = new ConnectivityController(jms, jms.getContext());
+            }
+            return mSingleton;
+        }
+    }
+
+    private ConnectivityController(StateChangedListener stateChangedListener, Context context) {
+        super(stateChangedListener, context);
+        // Register connectivity changed BR.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        mContext.registerReceiverAsUser(
+                mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
+        ConnectivityService cs =
+                (ConnectivityService)ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+        if (cs != null) {
+            if (cs.getActiveNetworkInfo() != null) {
+                mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
+            }
+            mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
+        }
+    }
+
+    @Override
+    public void maybeStartTrackingJob(JobStatus jobStatus) {
+        if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
+            synchronized (mTrackedJobs) {
+                jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
+                jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
+                mTrackedJobs.add(jobStatus);
+            }
+        }
+    }
+
+    @Override
+    public void maybeStopTrackingJob(JobStatus jobStatus) {
+        if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
+            synchronized (mTrackedJobs) {
+                mTrackedJobs.remove(jobStatus);
+            }
+        }
+    }
+
+    /**
+     * @param userId Id of the user for whom we are updating the connectivity state.
+     */
+    private void updateTrackedJobs(int userId) {
+        synchronized (mTrackedJobs) {
+            boolean changed = false;
+            for (JobStatus js : mTrackedJobs) {
+                if (js.getUserId() != userId) {
+                    continue;
+                }
+                boolean prevIsConnected =
+                        js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
+                boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
+                if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
+                    changed = true;
+                }
+            }
+            if (changed) {
+                mStateChangedListener.onControllerStateChanged();
+            }
+        }
+    }
+
+    /**
+     * We know the network has just come up. We want to run any jobs that are ready.
+     */
+    public synchronized void onNetworkActive() {
+        synchronized (mTrackedJobs) {
+            for (JobStatus js : mTrackedJobs) {
+                if (js.isReady()) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Running " + js + " due to network activity.");
+                    }
+                    mStateChangedListener.onRunJobNow(js);
+                }
+            }
+        }
+    }
+
+    class ConnectivityChangedReceiver extends BroadcastReceiver {
+        /**
+         * We'll receive connectivity changes for each user here, which we process independently.
+         * We are only interested in the active network here. We're only interested in the active
+         * network, b/c the end result of this will be for apps to try to hit the network.
+         * @param context The Context in which the receiver is running.
+         * @param intent The Intent being received.
+         */
+        // TODO: Test whether this will be called twice for each user.
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Slog.d(TAG, "Received connectivity event: " + intent.getAction() + " u"
+                        + context.getUserId());
+            }
+            final String action = intent.getAction();
+            if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+                final int networkType =
+                        intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
+                                ConnectivityManager.TYPE_NONE);
+                // Connectivity manager for THIS context - important!
+                final ConnectivityManager connManager = (ConnectivityManager)
+                        context.getSystemService(Context.CONNECTIVITY_SERVICE);
+                final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
+                final int userid = context.getUserId();
+                // This broadcast gets sent a lot, only update if the active network has changed.
+                if (activeNetwork == null) {
+                    mNetworkUnmetered = false;
+                    mNetworkConnected = false;
+                    updateTrackedJobs(userid);
+                } else if (activeNetwork.getType() == networkType) {
+                    mNetworkUnmetered = false;
+                    mNetworkConnected = !intent.getBooleanExtra(
+                            ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+                    if (mNetworkConnected) {  // No point making the call if we know there's no conn.
+                        mNetworkUnmetered = !connManager.isActiveNetworkMetered();
+                    }
+                    updateTrackedJobs(userid);
+                }
+            } else {
+                if (DEBUG) {
+                    Slog.d(TAG, "Unrecognised action in intent: " + action);
+                }
+            }
+        }
+    };
+
+    @Override
+    public void dumpControllerState(PrintWriter pw) {
+        pw.println("Conn.");
+        pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
+        for (JobStatus js: mTrackedJobs) {
+            pw.println(String.valueOf(js.hashCode()).substring(0, 3) + ".."
+                    + ": C=" + js.hasConnectivityConstraint()
+                    + ", UM=" + js.hasUnmeteredConstraint());
+        }
+    }
+}
\ No newline at end of file