Revision 441d5327

b/res/layout/createaccount.xml
1
<?xml version="1.0" encoding="utf-8"?>
2
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
	android:layout_width="fill_parent" android:layout_height="fill_parent"
4
	android:orientation="vertical">
5
	<TextView android:layout_height="wrap_content" android:text="Provider"
6
		android:layout_marginLeft="22dip" android:layout_width="fill_parent"></TextView>
7
	<Spinner android:layout_height="wrap_content"
8
		android:layout_marginLeft="22dip" android:layout_marginRight="30dip"
9
		android:layout_width="fill_parent" android:id="@+id/provider_spinner"></Spinner>
10
	<TextView android:layout_height="wrap_content" android:text="Username"
11
		android:layout_marginLeft="22dip" android:layout_width="fill_parent"></TextView>
12
	<EditText android:layout_width="fill_parent"
13
		android:layout_height="wrap_content" android:layout_marginLeft="22dip"
14
		android:layout_marginRight="30dip" android:id="@+id/username"></EditText>
15
	<TextView android:layout_height="wrap_content" android:text="API Key"
16
		android:layout_marginLeft="22dip" android:layout_width="fill_parent"></TextView>
17
	<EditText android:id="@+id/apikey"
18
		android:layout_height="wrap_content" android:layout_width="fill_parent"
19
		android:layout_marginLeft="22dip" android:layout_marginRight="30dip"
20
		android:scrollHorizontally="true" android:autoText="false"
21
		android:capitalize="none" android:gravity="fill_horizontal"
22
		android:singleLine="true" android:imeOptions="actionGo"
23
		android:inputType="textNoSuggestions" android:password="true"
24
		android:textAppearance="?android:attr/textAppearanceMedium" />
25
	<LinearLayout android:layout_height="wrap_content"
26
		android:layout_width="fill_parent" android:layout_marginTop="10dip">
27
		<Button android:layout_marginLeft="22dip"
28
			android:layout_height="wrap_content" android:text="Save"
29
			android:id="@+id/submit_new_account" android:layout_width="100dip"></Button>
30
		<CheckBox android:layout_width="wrap_content"
31
			android:layout_height="wrap_content" android:id="@+id/show_clear"
32
			android:text="Show API Key"></CheckBox>
33
	</LinearLayout>
34
</LinearLayout>
b/res/layout/listaccountcell.xml
1
<?xml version="1.0" encoding="utf-8"?>
2
<LinearLayout
3
  xmlns:android="http://schemas.android.com/apk/res/android"
4
  android:layout_width="fill_parent"
5
  android:orientation="horizontal" android:layout_height="64dip">
6
    <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/account_type_icon" android:src="@drawable/rackspace60"></ImageView>
7
    <TableLayout android:orientation="vertical" android:layout_height="fill_parent" android:layout_marginLeft="10dip" android:id="@+id/tableLayout1" android:layout_width="190dip">
8
        <TableRow android:layout_height="wrap_content" android:id="@+id/tableRow1" android:layout_width="wrap_content">
9
            <TextView android:textSize="24sp" android:textColor="#FFFFFF" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_marginTop="5px" android:id="@+id/label"></TextView>
10
        </TableRow>
11
        <TableRow android:layout_height="wrap_content" android:id="@+id/tableRow2" android:layout_width="wrap_content">
12
            <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/sublabel"></TextView>
13
        </TableRow>
14
    </TableLayout>
15
    <ProgressBar android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center" android:visibility="invisible" android:id="@+id/logon_progress_bar"></ProgressBar>
16
</LinearLayout>
b/res/layout/noaccountscell.xml
1
<?xml version="1.0" encoding="utf-8"?>
2
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
3
	android:id="@+id/linearLayout1"
4
	android:layout_width="fill_parent" 
5
	android:orientation="vertical"
6
	android:layout_height="264dip">
7
	<TextView android:text="No Accounts" 
8
		android:layout_width="fill_parent"
9
		android:layout_marginTop="125px" 
10
		android:gravity="center" 
11
		android:textColor="#FFFFFF" 
12
		android:textSize="24sp"
13
		android:layout_height="wrap_content" android:id="@+id/no_accounts_label">
14
	</TextView>
15
	<TextView android:text="Press the Menu button to create an account"
16
		android:layout_width="fill_parent" 
17
		android:layout_marginTop="10px"
18
		android:gravity="center"
19
		android:textColor="#FFFFFF"
20
		android:textSize="12sp"
21
		android:layout_height="wrap_content" android:id="@+id/no_accounts_sublabel">
22
	</TextView>
23
</LinearLayout>
b/res/layout/viewlistaccounts.xml
1
<?xml version="1.0" encoding="utf-8"?>
2
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
	android:layout_width="fill_parent" android:layout_height="fill_parent">
4
	<ListView xmlns:android="http://schemas.android.com/apk/res/android"
5
		android:layout_width="fill_parent" android:layout_height="0dip"
6
		android:layout_weight="1" android:stackFromBottom="true"
7
		android:transcriptMode="normal" android:id="@android:id/list" />
8
</LinearLayout>
b/res/menu/accounts_list_menu.xml
1
<?xml version="1.0" encoding="utf-8"?>
2
<menu xmlns:android="http://schemas.android.com/apk/res/android">
3
   <item android:id="@+id/add_account" android:title="New Account" android:icon="@drawable/add_button" />
4
</menu>
b/src/com/rackspacecloud/android/AddAccountActivity.java
1
package com.rackspacecloud.android;
2

  
3
import android.app.Activity;
4
import android.app.AlertDialog;
5
import android.content.DialogInterface;
6
import android.content.Intent;
7
import android.os.Bundle;
8
import android.text.method.PasswordTransformationMethod;
9
import android.text.method.SingleLineTransformationMethod;
10
import android.view.View;
11
import android.view.View.OnClickListener;
12
import android.widget.AdapterView.OnItemSelectedListener;
13
import android.widget.AdapterView;
14
import android.widget.ArrayAdapter;
15
import android.widget.Button;
16
import android.widget.CheckBox;
17
import android.widget.EditText;
18
import android.widget.Spinner;
19

  
20
public class AddAccountActivity extends Activity implements OnClickListener, OnItemSelectedListener{
21
	
22
	EditText usernameText;
23
	EditText apiKeyText;
24
	Spinner providerSpinner;
25
	String authServer;
26
	
27
	public void onCreate(Bundle savedInstanceState) {
28
        super.onCreate(savedInstanceState);
29
        setContentView(R.layout.createaccount);
30
        usernameText = (EditText) findViewById(R.id.username);
31
        apiKeyText = (EditText) findViewById(R.id.apikey);
32
        ((Button) findViewById(R.id.submit_new_account)).setOnClickListener(this);
33
        
34
        final CheckBox show_clear = (CheckBox) findViewById(R.id.show_clear);
35
        show_clear.setOnClickListener(new OnClickListener() {
36
        	@Override 
37
			public void onClick(View v) {
38
		        if (((CheckBox) v).isChecked()) {
39
		        	apiKeyText.setTransformationMethod(new SingleLineTransformationMethod());
40
		        } else {
41
		        	apiKeyText.setTransformationMethod(new PasswordTransformationMethod());	
42
		        }
43
		        apiKeyText.requestFocus();
44
		    }	
45
		});
46
        
47
        loadProviderSpinner();
48
    }
49
	
50
	private void loadProviderSpinner(){
51
		//set the auth server default to us
52
		authServer = "https://auth.api.rackspacecloud.com/v1.0";
53
		providerSpinner = (Spinner) findViewById(R.id.provider_spinner);
54
		String[] providers = {"Rackspace Cloud (US)", "Rackspace Cloud (UK)"};
55
		ArrayAdapter<String> imageAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, providers);
56
		imageAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
57
		providerSpinner.setAdapter(imageAdapter);
58
	}
59
	
60
	public void onClick(View arg0) {
61
		
62
		if (hasValidInput()) {
63
			//showActivityIndicators();
64
			Intent result = new Intent();
65
			Bundle b = new Bundle();
66
			b.putString("username", usernameText.getText().toString());
67
			b.putString("apiKey", apiKeyText.getText().toString());
68
			b.putString("server", authServer);
69
			result.putExtra("accountInfo", b);
70
			setResult(RESULT_OK, result);
71
			finish();
72
		} else {
73
			showAlert("Required Fields Missing", "Username and API Key are required.");
74
		}
75
		
76
	}
77
	
78
	private void showAlert(String title, String message) {
79
    	try {
80
		AlertDialog alert = new AlertDialog.Builder(this).create();
81
		alert.setTitle(title);
82
		alert.setMessage(message);
83
		alert.setButton("OK", new DialogInterface.OnClickListener() {
84
	      public void onClick(DialogInterface dialog, int which) {
85
	        return;
86
	    } }); 
87
		alert.show();
88
    	} catch (Exception e) {
89
    		e.printStackTrace();
90
    	}
91
    }
92
	
93
	private boolean hasValidInput() {
94
    	String username = usernameText.getText().toString();
95
    	String apiKey = apiKeyText.getText().toString();
96
    	return !"".equals(username) && !"".equals(apiKey);
97
    }
98
	
99
	public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
100
		if(position == 0){
101
			authServer = "https://auth.api.rackspacecloud.com/v1.0";
102
		}
103
		else{
104
			authServer = "https://lon.auth.api.rackspacecloud.com/v1.0";
105
		}
106
	}
107
	
108
	public void onNothingSelected(AdapterView<?> parent) {
109
	}
110
	
111

  
112
	
113
	
114

  
115
}
b/src/com/rackspacecloud/android/ListAccountsActivity.java
1
package com.rackspacecloud.android;
2

  
3
import java.io.File;
4
import java.io.FileInputStream;
5
import java.io.FileNotFoundException;
6
import java.io.FileOutputStream;
7
import java.io.IOException;
8
import java.io.ObjectInputStream;
9
import java.io.ObjectOutputStream;
10
import java.io.StreamCorruptedException;
11
import java.util.ArrayList;
12
import java.util.TreeMap;
13

  
14
import com.rackspace.cloud.servers.api.client.Account;
15
import com.rackspace.cloud.servers.api.client.Flavor;
16
import com.rackspace.cloud.servers.api.client.FlavorManager;
17
import com.rackspace.cloud.servers.api.client.Image;
18
import com.rackspace.cloud.servers.api.client.ImageManager;
19
import com.rackspace.cloud.servers.api.client.http.Authentication;
20

  
21
import android.app.AlertDialog;
22
import android.app.ListActivity;
23
import android.content.Context;
24
import android.content.DialogInterface;
25
import android.content.Intent;
26
import android.os.AsyncTask;
27
import android.os.Bundle;
28
import android.os.Environment;
29
import android.util.Log;
30
import android.view.LayoutInflater;
31
import android.view.Menu;
32
import android.view.MenuInflater;
33
import android.view.MenuItem;
34
import android.view.View;
35
import android.view.ViewGroup;
36
import android.widget.ArrayAdapter;
37
import android.widget.ImageView;
38
import android.widget.ListView;
39
import android.widget.ProgressBar;
40
import android.widget.TextView;
41

  
42
public class ListAccountsActivity extends ListActivity{
43

  
44
	private ArrayList<Account> accounts;
45
	private final String FILENAME = "accounts";
46
	private Intent tabViewIntent;
47
	private boolean authenticating;
48

  
49
	public void onCreate(Bundle savedInstanceState) {
50
        super.onCreate(savedInstanceState);
51
        restoreState(savedInstanceState);
52
        tabViewIntent = new Intent(this, TabViewActivity.class);
53
    }
54
	
55
	@Override
56
	protected void onSaveInstanceState(Bundle outState) {
57
		super.onSaveInstanceState(outState);
58
		outState.putBoolean("authenticating", authenticating);
59
		writeAccounts();
60
	}
61
	
62
	private void restoreState(Bundle state) {
63
		if (state != null && state.containsKey("authenticating") && state.getBoolean("authenticating")) {
64
    		showActivityIndicators();
65
    	} else {
66
    		hideActivityIndicators();
67
    	}
68
		if (state != null && state.containsKey("accounts")) {
69
    		accounts = readAccounts();
70
    		if (accounts.size() == 0) {
71
    			displayNoAccountsCell();
72
    		} else {
73
    			getListView().setDividerHeight(1); // restore divider lines 
74
    			setListAdapter(new AccountAdapter());
75
    		}
76
    	} else {
77
            loadAccounts();        
78
    	} 	
79
    }
80
	
81
	private void loadAccounts() {
82
		if(accounts == null){
83
			accounts = readAccounts();
84
		}
85
		//if nothing was written before accounts will still be null
86
		if(accounts == null){
87
			accounts = new ArrayList<Account>();
88
		}
89
		setAccountList();
90
	}
91

  
92
	private void setAccountList() {
93
	
94
		if (accounts == null) {
95
			accounts = new ArrayList<Account>();
96
		}
97
		if (accounts.size() == 0) {
98
			displayNoAccountsCell();
99
		} else {
100
			getListView().setDividerHeight(1); // restore divider lines 
101
			this.setListAdapter(new AccountAdapter());
102
		}
103
	}
104

  
105
	private void writeAccounts(){
106
		FileOutputStream fos;
107
		ObjectOutputStream out;
108
		try{
109
			fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
110
			out = new ObjectOutputStream(fos);
111
			out.writeObject(accounts);
112
			out.flush();
113
			out.close();
114
		} catch (FileNotFoundException e) {
115
			// TODO Auto-generated catch block
116
			e.printStackTrace();
117
		} catch (IOException e) {
118
			// TODO Auto-generated catch block
119
			e.printStackTrace();
120
		}
121
		
122
	}
123

  
124
	private ArrayList<Account> readAccounts(){
125
		FileInputStream fis;
126
		ObjectInputStream in;
127
		try {
128
			fis = openFileInput(FILENAME);
129
			in = new ObjectInputStream(fis);
130
			ArrayList<Account> file = (ArrayList<Account>)in.readObject();
131
			in.close();
132
			return file;
133
		} catch (FileNotFoundException e) {
134
			// TODO Auto-generated catch block
135
			e.printStackTrace();
136
			return null;
137
		} catch (StreamCorruptedException e) {
138
			// TODO Auto-generated catch block
139
			e.printStackTrace();
140
		} catch (IOException e) {
141
			// TODO Auto-generated catch block
142
			e.printStackTrace();
143
		} catch (ClassNotFoundException e) {
144
			// TODO Auto-generated catch block
145
			e.printStackTrace();
146
		}
147
		return null;
148
		
149
	}
150

  
151
	private void displayNoAccountsCell() {
152
    	String a[] = new String[1];
153
    	a[0] = "No Accounts";
154
        setListAdapter(new ArrayAdapter<String>(getApplicationContext(), R.layout.noaccountscell, R.id.no_accounts_label, a));
155
        getListView().setTextFilterEnabled(true);
156
        getListView().setDividerHeight(0); // hide the dividers so it won't look like a list row
157
        getListView().setItemsCanFocus(false);
158
    }
159
	
160
	protected void onListItemClick(ListView l, View v, int position, long id) {
161
		Account.setAccount(accounts.get(position));
162
		login();
163
		//Intent viewIntent = new Intent(this, TabViewActivity.class);
164
	    //viewIntent.putExtra("server", servers[position]);
165
		//startActivityForResult(viewIntent, 57); // arbitrary number; never used again
166
    		
167
    }
168
	
169
	public void login() {
170
        //showActivityIndicators();
171
        //setLoginPreferences();
172
        new AuthenticateTask().execute((Void[]) null);
173
    }
174
	
175
	
176
	public boolean onCreateOptionsMenu(Menu menu) {
177
		super.onCreateOptionsMenu(menu);
178
		MenuInflater inflater = getMenuInflater();
179
		inflater.inflate(R.menu.accounts_list_menu, menu);
180
		return true;
181
	} 
182
    
183
    @Override 
184
    public boolean onOptionsItemSelected(MenuItem item) {
185
		switch (item.getItemId()) {
186
		case R.id.add_account:
187
			startActivityForResult(new Intent(this, AddAccountActivity.class), 78); // arbitrary number; never used again
188
			return true;
189
		}
190
		return false;
191
	} 
192

  
193
	class AccountAdapter extends ArrayAdapter<Account> {
194

  
195
		AccountAdapter() {
196
			super(ListAccountsActivity.this, R.layout.listaccountcell, accounts);
197
		}
198
		
199
		public View getView(int position, View convertView, ViewGroup parent) {
200
			
201
			LayoutInflater inflater = getLayoutInflater();
202
			View row = inflater.inflate(R.layout.listaccountcell, parent, false);
203

  
204
			TextView label = (TextView) row.findViewById(R.id.label);
205
			label.setText(accounts.get(position).getUsername());
206
			
207
			TextView sublabel = (TextView) row.findViewById(R.id.sublabel);
208
			sublabel.setText(getAccountServer(accounts.get(position)));
209
			
210
			ImageView icon = (ImageView) row.findViewById(R.id.account_type_icon);
211
			icon.setImageResource(R.drawable.rackspace60);
212
			
213
			return row;
214
		}
215
	}
216
	
217
	public String getAccountServer(Account account){
218
		String authServer = account.getAuthServer();
219
		String result = "Rackspace Cloud";
220
		if(authServer.contains("lon")){
221
			result += " (UK)";
222
		}
223
		else{
224
			result += " (US)";
225
		}
226
		return result;
227
	}
228

  
229
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
230
		  super.onActivityResult(requestCode, resultCode, data);
231
		  
232
		  if (resultCode == RESULT_OK) {	  
233
			  Account acc = new Account();
234
			  Bundle b = data.getBundleExtra("accountInfo");
235
			  acc.setApiKey(b.getString("apiKey"));
236
			  acc.setUsername(b.getString("username"));
237
			  acc.setAuthServer(b.getString("server"));
238
			  accounts.add(acc);
239
			  loadAccounts();
240
		 }
241
	}	
242
	
243
	private void setActivityIndicatorsVisibility(int visibility) {
244
		//FINISH THIS TO LET USER KNOW PROGRAM IS STILL WORKING
245
		
246
        //ProgressBar pb = new ProgressBar();
247
    	//TextView tv = (TextView) findViewById(R.id.login_authenticating_label);
248
        //pb.setVisibility(visibility);
249
        //tv.setVisibility(visibility);
250
    }
251
	
252
	private void showActivityIndicators() {
253
    	setActivityIndicatorsVisibility(View.VISIBLE);
254
    }
255
    
256
    private void hideActivityIndicators() {
257
    	setActivityIndicatorsVisibility(View.INVISIBLE);
258
    }
259
	
260
	private class AuthenticateTask extends AsyncTask<Void, Void, Boolean> {
261
    	
262
		@Override
263
		protected Boolean doInBackground(Void... arg0) {
264
			Log.d("auth", "task1");
265
			authenticating = true;
266
			return new Boolean(Authentication.authenticate());
267
			//return true;
268
		}
269
    	
270
		@Override
271
		protected void onPostExecute(Boolean result) {
272
			authenticating = false;
273
			if (result.booleanValue()) {
274
				//startActivity(tabViewIntent);
275
	        	new LoadImagesTask().execute((Void[]) null);				
276
			} else {
277
				showAlert("Login Failure", "Authentication failed.  Please check your User Name and API Key.");
278
			}
279
		}
280
    }
281

  
282
    private class LoadFlavorsTask extends AsyncTask<Void, Void, ArrayList<Flavor>> {
283
    	
284
		@Override
285
		protected ArrayList<Flavor> doInBackground(Void... arg0) {
286
			Log.d("auth", "task2");
287
			return (new FlavorManager()).createList(true);
288
		}
289
    	
290
		@Override
291
		protected void onPostExecute(ArrayList<Flavor> result) {
292
			if (result != null && result.size() > 0) {
293
				TreeMap<String, Flavor> flavorMap = new TreeMap<String, Flavor>();
294
				for (int i = 0; i < result.size(); i++) {
295
					Flavor flavor = result.get(i);
296
					flavorMap.put(flavor.getId(), flavor);
297
				}
298
				Flavor.setFlavors(flavorMap);
299
				startActivity(tabViewIntent);
300
			} else {
301
				showAlert("Login Failure", "There was a problem loading server flavors.  Please try again.");
302
			}
303
			hideActivityIndicators();
304
		}
305
    }
306

  
307
    private class LoadImagesTask extends AsyncTask<Void, Void, ArrayList<Image>> {
308
    	
309
		@Override
310
		protected ArrayList<Image> doInBackground(Void... arg0) {
311
			Log.d("auth", "task3");
312
			return (new ImageManager()).createList(true);
313
		}
314
    	
315
		@Override
316
		protected void onPostExecute(ArrayList<Image> result) {
317
			if (result != null && result.size() > 0) {
318
				TreeMap<String, Image> imageMap = new TreeMap<String, Image>();
319
				for (int i = 0; i < result.size(); i++) {
320
					Image image = result.get(i);
321
					imageMap.put(image.getId(), image);
322
				}
323
				Image.setImages(imageMap);
324
				new LoadFlavorsTask().execute((Void[]) null);
325
				//startActivity(tabViewIntent);
326
			} else {
327
				showAlert("Login Failure", "There was a problem loading server images.  Please try again.");
328
			}
329
			hideActivityIndicators();
330
		}
331
    }
332
    
333
    private void showAlert(String title, String message) {
334
		AlertDialog alert = new AlertDialog.Builder(this).create();
335
		alert.setTitle(title);
336
		alert.setMessage(message);
337
		alert.setButton("OK", new DialogInterface.OnClickListener() {
338
	      public void onClick(DialogInterface dialog, int which) {
339
	        return;
340
	    } }); 
341
		alert.show();
342
		hideActivityIndicators();
343
    }
344
	
345
	
346
		
347
}

Also available in: Unified diff