1 /*******************************************************************************
2  * This file is part of BOINC.
3  * http://boinc.berkeley.edu
4  * Copyright (C) 2012 University of California
5  *
6  * BOINC is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation,
9  * either version 3 of the License, or (at your option) any later version.
10  *
11  * BOINC is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18  ******************************************************************************/
19 
20 package edu.berkeley.boinc.attach;
21 
22 import edu.berkeley.boinc.BOINCActivity;
23 import edu.berkeley.boinc.R;
24 import edu.berkeley.boinc.utils.*;
25 import android.app.Dialog;
26 import android.app.Service;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.ServiceConnection;
31 import android.net.ConnectivityManager;
32 import android.net.NetworkInfo;
33 import android.os.AsyncTask;
34 import android.os.Bundle;
35 import android.os.IBinder;
36 import android.support.v4.app.DialogFragment;
37 import android.util.Log;
38 import android.view.LayoutInflater;
39 import android.view.View;
40 import android.view.View.OnClickListener;
41 import android.view.ViewGroup;
42 import android.view.Window;
43 import android.widget.ArrayAdapter;
44 import android.widget.Button;
45 import android.widget.EditText;
46 import android.widget.LinearLayout;
47 import android.widget.Spinner;
48 import android.widget.TextView;
49 import android.widget.Toast;
50 
51 public class AcctMgrFragment extends DialogFragment{
52 
53 	private ProjectAttachService attachService = null;
54 	private boolean asIsBound = false;
55 
56 	private Spinner urlSpinner;
57 	private EditText nameInput;
58 	private EditText pwdInput;
59 	private TextView warning;
60 	private LinearLayout ongoingWrapper;
61 	private Button continueB;
62 
63 	private boolean returnToMainActivity = false;
64 
65 	private AttachProjectAsyncTask asyncTask;
66 
67     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)68 	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
69         if(Logging.DEBUG) Log.d(Logging.TAG, "AcctMgrFragment onCreateView");
70         doBindService();
71         View v = inflater.inflate(R.layout.attach_project_acctmgr_dialog, container, false);
72 
73         urlSpinner = (Spinner) v.findViewById(R.id.url_spinner);
74         ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(),R.array.acct_mgr_url_list, android.R.layout.simple_spinner_item);
75         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
76         urlSpinner.setAdapter(adapter);
77 
78         nameInput = (EditText) v.findViewById(R.id.name_input);
79         pwdInput = (EditText) v.findViewById(R.id.pwd_input);
80         warning = (TextView) v.findViewById(R.id.warning);
81         ongoingWrapper = (LinearLayout) v.findViewById(R.id.ongoing_wrapper);
82         continueB = (Button) v.findViewById(R.id.continue_button);
83         continueB.setOnClickListener(new OnClickListener() {
84 			@Override
85 			public void onClick(View arg0) {
86 		        if(Logging.DEBUG) Log.d(Logging.TAG, "AcctMgrFragment continue clicked");
87 				if(!checkDeviceOnline()) return;
88 		        if(asIsBound) {
89 
90 		    		// get user input
91 		    		String url = urlSpinner.getSelectedItem().toString();
92 		    		String name = nameInput.getText().toString();
93 		    		String pwd = pwdInput.getText().toString();
94 
95 		    		// verify input
96 		    		int res;
97 		    		if((res = verifyInput(url, name, pwd)) != 0){
98 		    			warning.setText(res);
99 		    			warning.setVisibility(View.VISIBLE);
100 		    			return;
101 		    		}
102 
103 		        	// adapt layout
104 		        	continueB.setVisibility(View.GONE);
105 					warning.setVisibility(View.GONE);
106 		        	ongoingWrapper.setVisibility(View.VISIBLE);
107 
108 		    		String[] params = new String[3];
109 		    		params[0] = url;
110 		    		params[1] = name;
111 		    		params[2] = pwd;
112 		    		asyncTask = new AttachProjectAsyncTask();
113 		    		asyncTask.execute(params);
114 
115 		        } else if(Logging.DEBUG) Log.d(Logging.TAG, "AcctMgrFragment service not bound, do nothing...");
116 			}
117         });
118 
119         return v;
120 	}
121 
122 	@Override
onDestroyView()123 	public void onDestroyView() {
124 		doUnbindService();
125 		if(asyncTask != null) asyncTask.cancel(true);
126 		super.onDestroyView();
127 	}
128 
129 	@Override
onCreateDialog(Bundle savedInstanceState)130 	public Dialog onCreateDialog(Bundle savedInstanceState) {
131 		  Dialog dialog = super.onCreateDialog(savedInstanceState);
132 
133 		  // request a window without the title
134 		  dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
135 		  return dialog;
136 	}
137 
setReturnToMainActivity()138 	public void setReturnToMainActivity() {
139 		returnToMainActivity = true;
140 	}
141 
verifyInput(String url, String name, String pwd)142 	private int verifyInput(String url, String name, String pwd) {
143 		int stringResource = 0;
144 
145 		// check input
146 		if(url.length() == 0) {
147 			stringResource = R.string.attachproject_error_no_url;
148 		}
149 		else if(name.length() == 0) {
150 			stringResource = R.string.attachproject_error_no_name;
151 		}
152 		else if(pwd.length() == 0) {
153 			stringResource = R.string.attachproject_error_no_pwd;
154 		}
155 
156 		return stringResource;
157 	}
158 
159 	// check whether device is online before starting connection attempt
160 	// as needed for AttachProjectLoginActivity (retrieval of ProjectConfig)
161 	// note: available internet does not imply connection to project server
162 	// is possible!
checkDeviceOnline()163 	private Boolean checkDeviceOnline() {
164 	    ConnectivityManager connectivityManager = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
165 	    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
166 	    Boolean online = activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting();
167 	    if(!online) {
168 	    	Toast toast = Toast.makeText(getActivity(), R.string.attachproject_list_no_internet, Toast.LENGTH_SHORT);
169 	    	toast.show();
170 	    	if(Logging.DEBUG) Log.d(Logging.TAG, "AttachProjectListActivity not online, stop!");
171 	    }
172 	    return online;
173 	}
174 
175 	private ServiceConnection mASConnection = new ServiceConnection() {
176 	    public void onServiceConnected(ComponentName className, IBinder service) {
177 	        // This is called when the connection with the service has been established, getService returns
178 	    	// the Monitor object that is needed to call functions.
179 	        attachService = ((ProjectAttachService.LocalBinder)service).getService();
180 		    asIsBound = true;
181 	    }
182 
183 	    public void onServiceDisconnected(ComponentName className) {
184 	    	// This should not happen
185 	    	attachService = null;
186 	    	asIsBound = false;
187 	    }
188 	};
189 
doBindService()190 	private void doBindService() {
191 		// bind to attach service
192 		getActivity().bindService(new Intent(getActivity(), ProjectAttachService.class), mASConnection, Service.BIND_AUTO_CREATE);
193 	}
194 
doUnbindService()195 	private void doUnbindService() {
196 	    if (asIsBound) {
197 	        // Detach existing connection.
198 	    	getActivity().unbindService(mASConnection);
199 	        asIsBound = false;
200 	    }
201 	}
202 
mapErrorNumToString(int code)203 	private String mapErrorNumToString(int code) {
204 		if(Logging.DEBUG) Log.d(Logging.TAG,"mapErrorNumToString for error: " + code);
205 		int stringResource;
206 		switch (code) {
207 		case BOINCErrors.ERR_DB_NOT_FOUND:
208 			stringResource = R.string.attachproject_error_wrong_name;
209 			break;
210 		case BOINCErrors.ERR_GETHOSTBYNAME:
211 			stringResource = R.string.attachproject_error_no_internet;
212 			break;
213 		case BOINCErrors.ERR_NONUNIQUE_EMAIL: // treat the same as -137, ERR_DB_NOT_UNIQUE
214 			// no break!!
215 		case BOINCErrors.ERR_DB_NOT_UNIQUE:
216 			stringResource =  R.string.attachproject_error_email_in_use;
217 			break;
218 		case BOINCErrors.ERR_PROJECT_DOWN:
219 			stringResource = R.string.attachproject_error_project_down;
220 			break;
221 		case BOINCErrors.ERR_BAD_EMAIL_ADDR:
222 			stringResource =  R.string.attachproject_error_email_bad_syntax;
223 			break;
224 		case BOINCErrors.ERR_BAD_PASSWD:
225 			stringResource = R.string.attachproject_error_bad_pwd;
226 			break;
227 		case BOINCErrors.ERR_BAD_USER_NAME:
228 			stringResource = R.string.attachproject_error_bad_username;
229 			break;
230 		case BOINCErrors.ERR_ACCT_CREATION_DISABLED:
231 			stringResource = R.string.attachproject_error_creation_disabled;
232 			break;
233 		case BOINCErrors.ERR_INVALID_URL:
234 			stringResource = R.string.attachproject_error_invalid_url;
235 			break;
236 		default:
237 			stringResource = R.string.attachproject_error_unknown;
238 			break;
239 		}
240 		return getString(stringResource);
241 	}
242 
243 	private class AttachProjectAsyncTask extends AsyncTask<String, Void, Integer> {
244 
245 		@Override
onPreExecute()246 		protected void onPreExecute() {
247 			super.onPreExecute();
248 		}
249 
250 		@Override
doInBackground(String... arg0)251 		protected Integer doInBackground(String... arg0) {
252 
253     		String url = arg0[0];
254     		String name = arg0[1];
255     		String pwd = arg0[2];
256 
257     		return attachService.attachAcctMgr(url,name,pwd);
258 		}
259 
260 		@Override
onPostExecute(Integer result)261 		protected void onPostExecute(Integer result) {
262 			super.onPostExecute(result);
263 			if(Logging.DEBUG) Log.d(Logging.TAG, "AcctMgrFragment.AttachProjectAsyncTask onPostExecute, returned: " + result);
264 			if(result == BOINCErrors.ERR_OK) {
265 				dismiss();
266 				if(returnToMainActivity) {
267 					if(Logging.DEBUG) Log.d(Logging.TAG, "AcctMgrFragment.AttachProjectAsyncTask onPostExecute, start main activity");
268 					Intent intent = new Intent(getActivity(), BOINCActivity.class);
269 					// add flags to return to main activity and clearing all others and clear the back stack
270 					intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
271 					intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
272 					intent.putExtra("targetFragment", R.string.tab_projects); // make activity display projects fragment
273 					startActivity(intent);
274 				}
275 			}
276 			else {
277 	        	ongoingWrapper.setVisibility(View.GONE);
278 	        	continueB.setVisibility(View.VISIBLE);
279 				warning.setVisibility(View.VISIBLE);
280 				warning.setText(mapErrorNumToString(result));
281 			}
282 		}
283 	}
284 }
285