blob: 09da403cadf1312334fe4fbcadc0f033dd771bbb [file] [log] [blame]
Adrien BĂ©raud04d822c2015-04-02 17:44:36 -04001/*
2 * Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
3 *
4 * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
5 * Alexandre Lision <alexandre.lision@savoirfairelinux.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * Additional permission under GNU GPL version 3 section 7:
22 *
23 * If you modify this program, or any covered work, by linking or
24 * combining it with the OpenSSL project's OpenSSL library (or a
25 * modified version of that library), containing parts covered by the
26 * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
27 * grants you additional permission to convey the resulting work.
28 * Corresponding Source for a non-source form of such a combination
29 * shall include the source code for the parts of OpenSSL used as well
30 * as that of the covered work.
31 */
32
33package cx.ring.fragments;
34
35import android.animation.Animator;
36import android.animation.AnimatorListenerAdapter;
37import android.app.Activity;
38import android.content.Context;
39import android.content.Intent;
40import android.os.Bundle;
41import android.os.RemoteException;
42import android.support.v4.app.LoaderManager;
43import android.support.v4.content.AsyncTaskLoader;
44import android.support.v4.content.Loader;
45import android.util.Log;
46import android.view.*;
47import android.view.View.OnClickListener;
48import android.widget.*;
49import android.widget.AdapterView.OnItemClickListener;
50import cx.ring.R;
51import cx.ring.client.AccountEditionActivity;
52import cx.ring.client.AccountWizard;
53import cx.ring.loaders.AccountsLoader;
54import cx.ring.loaders.LoaderConstants;
55import cx.ring.model.account.Account;
56import cx.ring.service.ISipService;
57import cx.ring.views.dragsortlv.DragSortListView;
58
59import java.io.File;
60import java.util.ArrayList;
61
62public class AccountsManagementFragment extends AccountWrapperFragment implements LoaderManager.LoaderCallbacks<Bundle> {
63 static final String TAG = "AccountManagementFragment";
64 static final String DEFAULT_ACCOUNT_ID = "IP2IP";
65 static final int ACCOUNT_CREATE_REQUEST = 1;
66 public static final int ACCOUNT_EDIT_REQUEST = 2;
67 AccountsAdapter mAccountsAdapter;
68 AccountsAdapter mIP2IPAdapter;
69
70 DragSortListView mDnDListView;
71 private View mLoadingView;
72 private int mShortAnimationDuration;
73
74 private DragSortListView.DropListener onDrop = new DragSortListView.DropListener() {
75 @Override
76 public void drop(int from, int to) {
77 if (from != to) {
78 Account item = mAccountsAdapter.getItem(from);
79 mAccountsAdapter.remove(item);
80 mAccountsAdapter.insert(item, to);
81 try {
82 mCallbacks.getService().setAccountOrder(mAccountsAdapter.generateAccountOrder());
83 } catch (RemoteException e) {
84 e.printStackTrace();
85 }
86 }
87 }
88
89 };
90
91 private Callbacks mCallbacks = sDummyCallbacks;
92 private Account ip2ip;
93 private static Callbacks sDummyCallbacks = new Callbacks() {
94
95 @Override
96 public ISipService getService() {
97 return null;
98 }
99 };
100 private AccountsLoader accountsLoader;
101
102 public interface Callbacks {
103
104 public ISipService getService();
105
106 }
107
108 @Override
109 public void onAttach(Activity activity) {
110 super.onAttach(activity);
111 if (!(activity instanceof Callbacks)) {
112 throw new IllegalStateException("Activity must implement fragment's callbacks.");
113 }
114
115 mCallbacks = (Callbacks) activity;
116 }
117
118 @Override
119 public void onDetach() {
120 super.onDetach();
121 mCallbacks = sDummyCallbacks;
122 }
123
124 @Override
125 public void onCreate(Bundle savedInstanceState) {
126 super.onCreate(savedInstanceState);
127
128 Log.i(TAG, "Create Account Management Fragment");
129 mAccountsAdapter = new AccountsAdapter(getActivity(), new ArrayList<Account>());
130 mIP2IPAdapter = new AccountsAdapter(getActivity(), new ArrayList<Account>());
131 this.setHasOptionsMenu(true);
132
133 mShortAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);
134 Log.i(TAG, "anim time: " + mShortAnimationDuration);
135 getLoaderManager().initLoader(LoaderConstants.ACCOUNTS_LOADER, null, this);
136 }
137
138 @Override
139 public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
140 View inflatedView = inflater.inflate(R.layout.frag_accounts_list, parent, false);
141 ((ListView)inflatedView.findViewById(R.id.accounts_list)).setAdapter(mAccountsAdapter);
142
143 return inflatedView;
144 }
145
146 @Override
147 public void onViewCreated(View view, Bundle savedInstanceState) {
148 super.onViewCreated(view, savedInstanceState);
149
150 mDnDListView = (DragSortListView) getView().findViewById(R.id.accounts_list);
151
152 mDnDListView.setDropListener(onDrop);
153 mDnDListView.setOnItemClickListener(new OnItemClickListener() {
154
155 @Override
156 public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
157 launchAccountEditActivity(mAccountsAdapter.getItem(pos));
158 }
159 });
160
161 ((ListView) getView().findViewById(R.id.ip2ip)).setAdapter(mIP2IPAdapter);
162 ((ListView) getView().findViewById(R.id.ip2ip)).setOnItemClickListener(new OnItemClickListener() {
163
164 @Override
165 public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
166 launchAccountEditActivity(ip2ip);
167
168 }
169 });
170
171 mLoadingView = view.findViewById(R.id.loading_spinner);
172 }
173
174 @Override
175 public void onPause() {
176 super.onPause();
177 }
178
179 public void onResume() {
180 super.onResume();
181 accountsLoader.onContentChanged();
182 getActivity().getActionBar().setTitle(R.string.menu_item_accounts);
183 }
184
185 @Override
186 public void onCreateOptionsMenu(Menu m, MenuInflater inf) {
187 super.onCreateOptionsMenu(m, inf);
188 inf.inflate(R.menu.account_creation, m);
189 }
190
191 @Override
192 public boolean onOptionsItemSelected(MenuItem item) {
193 super.onOptionsItemSelected(item);
194 switch (item.getItemId()) {
195 case R.id.menuitem_create:
196 Intent intent = new Intent().setClass(getActivity(), AccountWizard.class);
197 startActivityForResult(intent, ACCOUNT_CREATE_REQUEST);
198 break;
199 }
200
201 return true;
202 }
203
204 private void launchAccountEditActivity(Account acc) {
205 Log.i(TAG, "Launch account edit activity");
206
207 Intent intent = new Intent().setClass(getActivity(), AccountEditionActivity.class);
208 Bundle bundle = new Bundle();
209 bundle.putParcelable("account", acc);
210
211 intent.putExtras(bundle);
212
213 startActivityForResult(intent, ACCOUNT_EDIT_REQUEST);
214 }
215
216 @Override
217 public void accountsChanged() {
218 accountsLoader.onContentChanged();
219 }
220
221 @Override
222 public void accountStateChanged(String accoundID, String state, int code) {
223 mAccountsAdapter.updateAccount(accoundID, state, code);
224 }
225
226 @Override
227 public void onActivityResult(int requestCode, int resultCode, Intent data) {
228 super.onActivityResult(requestCode, resultCode, data);
229 accountsLoader.onContentChanged();
230 }
231
232 /**
233 * Adapter for accounts List
234 *
235 * @author lisional
236 */
237 public class AccountsAdapter extends BaseAdapter {
238
239 // private static final String TAG = AccountSelectionAdapter.class.getSimpleName();
240
241 ArrayList<Account> accounts;
242 Context mContext;
243
244 public AccountsAdapter(Context cont, ArrayList<Account> newList) {
245 super();
246 accounts = newList;
247 mContext = cont;
248 }
249
250 public void insert(Account item, int to) {
251 accounts.add(to, item);
252 notifyDataSetChanged();
253 }
254
255 public void remove(Account item) {
256 accounts.remove(item);
257 notifyDataSetChanged();
258 }
259
260 @Override
261 public boolean hasStableIds() {
262 return true;
263 }
264
265 @Override
266 public int getCount() {
267 return accounts.size();
268 }
269
270 @Override
271 public Account getItem(int pos) {
272 return accounts.get(pos);
273 }
274
275 @Override
276 public long getItemId(int pos) {
277 return 0;
278 }
279
280 @Override
281 public View getView(final int pos, View convertView, ViewGroup parent) {
282 View rowView = convertView;
283 AccountView entryView;
284
285 if (rowView == null) {
286 LayoutInflater inflater = LayoutInflater.from(mContext);
287 rowView = inflater.inflate(R.layout.item_account_pref, null);
288
289 entryView = new AccountView();
290 entryView.alias = (TextView) rowView.findViewById(R.id.account_alias);
291 entryView.host = (TextView) rowView.findViewById(R.id.account_host);
292 entryView.enabled = (CheckBox) rowView.findViewById(R.id.account_checked);
293 rowView.setTag(entryView);
294 } else {
295 entryView = (AccountView) rowView.getTag();
296 }
297
298 final Account item = accounts.get(pos);
299 entryView.alias.setText(accounts.get(pos).getAlias());
300 if (item.isIP2IP()) {
301 entryView.host.setText(item.getRegistered_state());
302 entryView.enabled.setVisibility(View.GONE);
303 } else {
304 entryView.host.setText(item.getHost() + " - " + item.getRegistered_state());
305 entryView.enabled.setChecked(item.isEnabled());
306 entryView.enabled.setOnClickListener(new OnClickListener() {
307
308 @Override
309 public void onClick(View v) {
310 item.setEnabled(!item.isEnabled());
311
312 try {
313 mCallbacks.getService().setAccountDetails(item.getAccountID(), item.getDetails());
314 } catch (RemoteException e) {
315 e.printStackTrace();
316 }
317 }
318 });
319 }
320
321 return rowView;
322 }
323
324 /**
325 * ******************
326 * ViewHolder Pattern
327 * *******************
328 */
329 public class AccountView {
330 public TextView alias;
331 public TextView host;
332 public CheckBox enabled;
333 }
334
335 public void removeAll() {
336 accounts.clear();
337 notifyDataSetChanged();
338
339 }
340
341 public void addAll(ArrayList<Account> results) {
342 accounts.addAll(results);
343 notifyDataSetChanged();
344 }
345
346 /**
347 * Modify state of specific account
348 */
349 public void updateAccount(String accoundID, String state, int code) {
350 Log.i(TAG, "updateAccount:" + state);
351 for (Account a : accounts) {
352 if (a.getAccountID().contentEquals(accoundID)) {
353 a.setRegistered_state(state);
354 notifyDataSetChanged();
355 return;
356 }
357 }
358
359 }
360
361 private String generateAccountOrder() {
362 String result = DEFAULT_ACCOUNT_ID + File.separator;
363 for (Account a : accounts) {
364 result += a.getAccountID() + File.separator;
365 }
366 return result;
367 }
368
369 }
370
371 private void crossfade() {
372
373 // Set the content view to 0% opacity but visible, so that it is visible
374 // (but fully transparent) during the animation.
375 mDnDListView.setAlpha(0f);
376 mDnDListView.setVisibility(View.VISIBLE);
377
378 // Animate the content view to 100% opacity, and clear any animation
379 // listener set on the view.
380 mDnDListView.animate().alpha(1f).setDuration(mShortAnimationDuration).setListener(null);
381
382 // Animate the loading view to 0% opacity. After the animation ends,
383 // set its visibility to GONE as an optimization step (it won't
384 // participate in layout passes, etc.)
385 mLoadingView.animate().alpha(0f).setDuration(mShortAnimationDuration).setListener(new AnimatorListenerAdapter() {
386 @Override
387 public void onAnimationEnd(Animator animation) {
388 mLoadingView.setVisibility(View.GONE);
389 }
390 });
391 }
392
393
394 @Override
395 public AsyncTaskLoader<Bundle> onCreateLoader(int arg0, Bundle arg1) {
396 accountsLoader = new AccountsLoader(getActivity(), mCallbacks.getService());
397 return accountsLoader;
398 }
399
400 @Override
401 public void onLoadFinished(Loader<Bundle> bundleLoader, Bundle results) {
402 mAccountsAdapter.removeAll();
403 ArrayList<Account> tmp = results.getParcelableArrayList(AccountsLoader.ACCOUNTS);
404 ip2ip = results.getParcelable(AccountsLoader.ACCOUNT_IP2IP);
405 mAccountsAdapter.addAll(tmp);
406 mIP2IPAdapter.removeAll();
407 mIP2IPAdapter.insert(ip2ip, 0);
408 if (mAccountsAdapter.isEmpty()) {
409 mDnDListView.setEmptyView(getView().findViewById(R.id.empty_account_list));
410 }
411 crossfade();
412 }
413
414 @Override
415 public void onLoaderReset(Loader<Bundle> bundleLoader) {
416
417 }
418
419}