1 package com.android.cts.verifier.jobscheduler;
2 
3 import android.annotation.TargetApi;
4 import android.app.job.JobInfo;
5 import android.content.BroadcastReceiver;
6 import android.content.Context;
7 import android.content.Intent;
8 import android.content.IntentFilter;
9 import android.net.ConnectivityManager;
10 import android.net.NetworkInfo;
11 import android.os.AsyncTask;
12 import android.os.Bundle;
13 import android.util.Log;
14 import android.widget.Button;
15 import android.widget.ImageView;
16 
17 import com.android.cts.verifier.R;
18 
19 /**
20  * The majority of the connectivity constraints are done in the device-side test app
21  * android.jobscheduler.cts.deviceside. However a manual tester is required to completely turn off
22  * connectivity on the device in order to verify that jobs with connectivity constraints will not
23  * run in the absence of an internet connection.
24  */
25 @TargetApi(21)
26 public class ConnectivityConstraintTestActivity extends ConstraintTestActivity {
27     private static final String TAG = "ConnectivityConstraintTestActivity";
28     private static final int ANY_CONNECTIVITY_JOB_ID =
29             ConnectivityConstraintTestActivity.class.hashCode() + 0;
30     private static final int UNMETERED_CONNECTIVITY_JOB_ID =
31             ConnectivityConstraintTestActivity.class.hashCode() + 1;
32     private static final int NO_CONNECTIVITY_JOB_ID =
33             ConnectivityConstraintTestActivity.class.hashCode() + 2;
34     private static final int NO_CONNECTIVITY_JOB_ID_2 =
35             ConnectivityConstraintTestActivity.class.hashCode() + 3;
36 
37     @Override
onCreate(Bundle savedInstanceState)38     protected void onCreate(Bundle savedInstanceState) {
39         super.onCreate(savedInstanceState);
40 
41         // Set up the UI.
42         setContentView(R.layout.js_connectivity);
43         setPassFailButtonClickListeners();
44         setInfoResources(R.string.js_connectivity_test, R.string.js_connectivity_instructions, -1);
45         mStartButton = (Button) findViewById(R.id.js_connectivity_start_test_button);
46 
47         // Disable test start if there is data connectivity.
48         mStartButton.setEnabled(isDataUnavailable());
49         // Register receiver to listen for connectivity changes.
50         IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
51         registerReceiver(mConnectivityChangedReceiver, intentFilter);
52 
53     }
54 
55     @Override
onDestroy()56     protected void onDestroy() {
57         super.onDestroy();
58         unregisterReceiver(mConnectivityChangedReceiver);
59     }
60 
61     @Override
startTestImpl()62     protected void startTestImpl() {
63         new TestConnectivityConstraint().execute();
64     }
65 
66     /** Ensure that there's no connectivity before we allow the test to start. */
67     BroadcastReceiver mConnectivityChangedReceiver = new BroadcastReceiver() {
68         @Override
69         public void onReceive(Context context, Intent intent) {
70             Log.d(TAG, "received: " + intent);
71             String extras = "";
72             for (String name : intent.getExtras().keySet()) {
73                 extras += " |" + name + " " + intent.getExtras().get(name) + "|";
74 
75             }
76             Log.d(TAG, "extras: " + extras);
77             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
78                 // Only enable the test when we know there is no connectivity.
79                 mStartButton.setEnabled(isDataUnavailable());
80             }
81         }
82     };
83 
testUnmeteredConstraintFails_noConnectivity()84     private void testUnmeteredConstraintFails_noConnectivity() {
85         testConnectivityConstraintFailsImpl(
86                 JobInfo.NETWORK_TYPE_UNMETERED, UNMETERED_CONNECTIVITY_JOB_ID);
87     }
88 
testAnyConnectivityConstraintFails_noConnectivity()89     private void testAnyConnectivityConstraintFails_noConnectivity() {
90         testConnectivityConstraintFailsImpl(JobInfo.NETWORK_TYPE_ANY, ANY_CONNECTIVITY_JOB_ID);
91     }
92 
testNoConnectivityConstraintExecutes_noConnectivity()93     private void testNoConnectivityConstraintExecutes_noConnectivity() {
94         JobInfo testJob1 = new JobInfo.Builder(NO_CONNECTIVITY_JOB_ID, mMockComponent)
95                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
96                 .setOverrideDeadline(100000L)  // Will not expire.
97                 .build();
98         JobInfo testJob2 = new JobInfo.Builder(NO_CONNECTIVITY_JOB_ID_2, mMockComponent)
99         .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
100         .setOverrideDeadline(100000L)  // Will not expire.
101         .build();
102 
103         mTestEnvironment.setUp();
104         mTestEnvironment.setExpectedExecutions(2);
105 
106         mJobScheduler.schedule(testJob1);
107         mJobScheduler.schedule(testJob2);
108 
109         boolean testPassed;
110         try {
111             testPassed = mTestEnvironment.awaitExecution();
112         } catch (InterruptedException e) {
113             testPassed = false;
114         }
115         runOnUiThread(
116                 new ConnectivityConstraintTestResultRunner(NO_CONNECTIVITY_JOB_ID, testPassed));
117     }
118 
testConnectivityConstraintFailsImpl(int requiredNetworkType, int jobId)119     private void testConnectivityConstraintFailsImpl(int requiredNetworkType, int jobId) {
120         // Use arguments provided to construct job with required connectivity constraint.
121         JobInfo testJob = new JobInfo.Builder(jobId, mMockComponent)
122                 .setRequiredNetworkType(requiredNetworkType)
123                 .build();
124 
125         mTestEnvironment.setUp();
126         mTestEnvironment.setExpectedExecutions(0);
127 
128         mJobScheduler.schedule(testJob);
129 
130         boolean testPassed;
131         try {
132             testPassed = mTestEnvironment.awaitTimeout();
133         } catch (InterruptedException e) {
134             testPassed = false;
135         }
136         runOnUiThread(
137                 new ConnectivityConstraintTestResultRunner(jobId, testPassed));
138     }
139 
140     /** Query the active network connection and return if there is no data connection. */
isDataUnavailable()141     private boolean isDataUnavailable() {
142         final ConnectivityManager cm =
143                 (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
144         final NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
145 
146         return (activeNetwork == null) ||
147                 !activeNetwork.isConnectedOrConnecting();
148     }
149 
150     private class TestConnectivityConstraint extends AsyncTask<Void, Void, Void> {
151 
152         @Override
doInBackground(Void... voids)153         protected Void doInBackground(Void... voids) {
154             testUnmeteredConstraintFails_noConnectivity();
155             testAnyConnectivityConstraintFails_noConnectivity();
156             testNoConnectivityConstraintExecutes_noConnectivity();
157 
158             notifyTestCompleted();
159             return null;
160         }
161     }
162 
163     private class ConnectivityConstraintTestResultRunner extends TestResultRunner {
ConnectivityConstraintTestResultRunner(int jobId, boolean testPassed)164         ConnectivityConstraintTestResultRunner(int jobId, boolean testPassed) {
165             super(jobId, testPassed);
166         }
167 
168         @Override
run()169         public void run() {
170             ImageView view;
171             if (mJobId == ANY_CONNECTIVITY_JOB_ID) {
172                 view = (ImageView) findViewById(R.id.connectivity_off_test_any_connectivity_image);
173             } else if (mJobId == UNMETERED_CONNECTIVITY_JOB_ID) {
174                 view = (ImageView) findViewById(R.id.connectivity_off_test_unmetered_image);
175             } else if (mJobId == NO_CONNECTIVITY_JOB_ID) {
176                 view = (ImageView) findViewById(R.id.connectivity_off_test_no_connectivity_image);
177             } else {
178                 noteInvalidTest();
179                 return;
180             }
181             view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
182         }
183     }
184 
185 }
186