1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 package org.mozilla.gecko.overlays.ui;
6 
7 import java.util.Collection;
8 
9 import org.mozilla.gecko.AppConstants;
10 import org.mozilla.gecko.R;
11 import org.mozilla.gecko.db.RemoteClient;
12 import org.mozilla.gecko.overlays.ui.SendTabList.State;
13 
14 import android.app.AlertDialog;
15 import android.content.Context;
16 import android.graphics.drawable.Drawable;
17 import android.view.View;
18 import android.view.View.OnClickListener;
19 import android.view.ViewGroup;
20 import android.widget.ArrayAdapter;
21 
22 public class SendTabDeviceListArrayAdapter extends ArrayAdapter<RemoteClient> {
23     @SuppressWarnings("unused")
24     private static final String LOGTAG = "GeckoSendTabAdapter";
25 
26     private State currentState;
27 
28     // String to display when in a "button-like" special state. Instead of using a
29     // RemoteClient we override the rendering using this string.
30     private String dummyRecordName;
31 
32     private final SendTabTargetSelectedListener listener;
33 
34     private Collection<RemoteClient> records;
35 
36     // The AlertDialog to show in the event the record is pressed while in the SHOW_DEVICES state.
37     // This will show the user a prompt to select a device from a longer list of devices.
38     private AlertDialog dialog;
39 
SendTabDeviceListArrayAdapter(Context context, SendTabTargetSelectedListener aListener)40     public SendTabDeviceListArrayAdapter(Context context, SendTabTargetSelectedListener aListener) {
41         super(context, R.layout.overlay_share_send_tab_item, R.id.overlaybtn_label);
42 
43         listener = aListener;
44 
45         // We do this manually and avoid multiple notifications when doing compound operations.
46         setNotifyOnChange(false);
47     }
48 
49     /**
50      * Get an array of the contents of this adapter were it in the LIST state.
51      * Useful for determining the "real" contents of the adapter.
52      */
toArray()53     public RemoteClient[] toArray() {
54         return records.toArray(new RemoteClient[records.size()]);
55     }
56 
setRemoteClientsList(Collection<RemoteClient> remoteClientsList)57     public void setRemoteClientsList(Collection<RemoteClient> remoteClientsList) {
58         records = remoteClientsList;
59         updateRecordList();
60     }
61 
62     /**
63      * Ensure the contents of the Adapter are synchronised with the `records` field. This may not
64      * be the case if records has recently changed, or if we have experienced a state change.
65      */
updateRecordList()66     public void updateRecordList() {
67         if (currentState != State.LIST) {
68             return;
69         }
70 
71         clear();
72 
73         setNotifyOnChange(false);    // So we don't notify for each add.
74         addAll(records);
75 
76         notifyDataSetChanged();
77     }
78 
79     @Override
getView(final int position, View convertView, ViewGroup parent)80     public View getView(final int position, View convertView, ViewGroup parent) {
81         final Context context = getContext();
82 
83         // Reuse View objects if they exist.
84         OverlayDialogButton row = (OverlayDialogButton) convertView;
85         if (row == null) {
86             row = (OverlayDialogButton) View.inflate(context, R.layout.overlay_share_send_tab_item, null);
87         }
88 
89         // The first view in the list has a unique style.
90         if (position == 0) {
91             row.setBackgroundResource(R.drawable.overlay_share_button_background_first);
92         } else {
93             row.setBackgroundResource(R.drawable.overlay_share_button_background);
94         }
95 
96         if (currentState != State.LIST) {
97             // If we're in a special "Button-like" state, use the override string and a generic icon.
98             final Drawable sendTabIcon = context.getResources().getDrawable(R.drawable.shareplane);
99             row.setText(dummyRecordName);
100             row.setDrawable(sendTabIcon);
101         }
102 
103         // If we're just a button to launch the dialog, set the listener and abort.
104         if (currentState == State.SHOW_DEVICES) {
105             row.setOnClickListener(new OnClickListener() {
106                 @Override
107                 public void onClick(View view) {
108                     dialog.show();
109                 }
110             });
111 
112             return row;
113         }
114 
115         // The remaining states delegate to the SentTabTargetSelectedListener.
116         final RemoteClient remoteClient = getItem(position);
117         if (currentState == State.LIST) {
118             final Drawable clientIcon = context.getResources().getDrawable(getImage(remoteClient));
119             row.setText(remoteClient.name);
120             row.setDrawable(clientIcon);
121 
122             final String listenerGUID = remoteClient.guid;
123 
124             row.setOnClickListener(new OnClickListener() {
125                 @Override
126                 public void onClick(View view) {
127                     listener.onSendTabTargetSelected(listenerGUID);
128                 }
129             });
130         } else {
131             row.setOnClickListener(new OnClickListener() {
132                 @Override
133                 public void onClick(View view) {
134                     listener.onSendTabActionSelected();
135                 }
136             });
137         }
138 
139         return row;
140     }
141 
getImage(RemoteClient record)142     private static int getImage(RemoteClient record) {
143         if ("mobile".equals(record.deviceType)) {
144             return R.drawable.device_mobile;
145         }
146 
147         return R.drawable.device_desktop;
148     }
149 
switchState(State newState)150     public void switchState(State newState) {
151         if (currentState == newState) {
152             return;
153         }
154 
155         currentState = newState;
156 
157         switch (newState) {
158             case LIST:
159                 updateRecordList();
160                 break;
161             case NONE:
162                 showDummyRecord(getContext().getResources().getString(R.string.overlay_share_send_tab_btn_label));
163                 break;
164             case SHOW_DEVICES:
165                 showDummyRecord(getContext().getResources().getString(R.string.overlay_share_send_other));
166                 break;
167             default:
168                 throw new IllegalStateException("Unexpected state transition: " + newState);
169         }
170     }
171 
172     /**
173      * Set the dummy override string to the given value and clear the list.
174      */
showDummyRecord(String name)175     private void showDummyRecord(String name) {
176         dummyRecordName = name;
177         clear();
178         add(null);
179         notifyDataSetChanged();
180     }
181 
setDialog(AlertDialog aDialog)182     public void setDialog(AlertDialog aDialog) {
183         dialog = aDialog;
184     }
185 }
186