1 /*
2  * Copyright (C) 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.googlecode.android_scripting.activity;
18 
19 import android.app.AlertDialog;
20 import android.app.ListActivity;
21 import android.content.DialogInterface;
22 import android.content.Intent;
23 import android.content.DialogInterface.OnClickListener;
24 import android.os.Bundle;
25 import android.view.ContextMenu;
26 import android.view.Menu;
27 import android.view.MenuItem;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.view.ContextMenu.ContextMenuInfo;
31 import android.widget.AdapterView;
32 import android.widget.BaseAdapter;
33 import android.widget.ListView;
34 import android.widget.TextView;
35 
36 import com.google.common.collect.Lists;
37 import com.googlecode.android_scripting.ActivityFlinger;
38 import com.googlecode.android_scripting.BaseApplication;
39 import com.googlecode.android_scripting.Constants;
40 import com.googlecode.android_scripting.Log;
41 import com.googlecode.android_scripting.R;
42 import com.googlecode.android_scripting.facade.FacadeConfiguration;
43 import com.googlecode.android_scripting.rpc.MethodDescriptor;
44 import com.googlecode.android_scripting.trigger.ScriptTrigger;
45 import com.googlecode.android_scripting.trigger.Trigger;
46 import com.googlecode.android_scripting.trigger.TriggerRepository;
47 import com.googlecode.android_scripting.trigger.TriggerRepository.TriggerRepositoryObserver;
48 
49 import java.io.File;
50 import java.util.Collections;
51 import java.util.List;
52 import java.util.Map;
53 
54 public class TriggerManager extends ListActivity {
55   private final List<ScriptTrigger> mTriggers = Lists.newArrayList();
56 
57   private ScriptTriggerAdapter mAdapter;
58   private TriggerRepository mTriggerRepository;
59 
60   private static enum ContextMenuId {
61     REMOVE;
getId()62     public int getId() {
63       return ordinal() + Menu.FIRST;
64     }
65   }
66 
67   private static enum MenuId {
68     ADD, PREFERENCES, HELP;
getId()69     public int getId() {
70       return ordinal() + Menu.FIRST;
71     }
72   }
73 
74   @Override
onCreate(Bundle savedInstanceState)75   protected void onCreate(Bundle savedInstanceState) {
76     super.onCreate(savedInstanceState);
77     CustomizeWindow.requestCustomTitle(this, "Triggers", R.layout.trigger_manager);
78     ScriptTriggerListObserver observer = new ScriptTriggerListObserver();
79     mAdapter = new ScriptTriggerAdapter();
80     setListAdapter(mAdapter);
81     registerForContextMenu(getListView());
82     mTriggerRepository = ((BaseApplication) getApplication()).getTriggerRepository();
83     mTriggerRepository.bootstrapObserver(observer);
84     ActivityFlinger.attachView(getListView(), this);
85     ActivityFlinger.attachView(getWindow().getDecorView(), this);
86   }
87 
88   @Override
onCreateOptionsMenu(Menu menu)89   public boolean onCreateOptionsMenu(Menu menu) {
90     menu.add(Menu.NONE, MenuId.ADD.getId(), Menu.NONE, "Add").setIcon(
91         android.R.drawable.ic_menu_add);
92     menu.add(Menu.NONE, MenuId.PREFERENCES.getId(), Menu.NONE, "Preferences").setIcon(
93         android.R.drawable.ic_menu_preferences);
94     return true;
95   }
96 
97   @Override
onOptionsItemSelected(MenuItem item)98   public boolean onOptionsItemSelected(MenuItem item) {
99     int itemId = item.getItemId();
100     if (itemId == MenuId.PREFERENCES.getId()) {
101       startActivity(new Intent(this, Preferences.class));
102     } else if (itemId != Menu.NONE) {
103       Intent intent = new Intent(this, ScriptPicker.class);
104       intent.setAction(Intent.ACTION_PICK);
105       startActivityForResult(intent, itemId);
106     }
107     return true;
108   }
109 
110   @Override
onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)111   public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
112     menu.add(Menu.NONE, ContextMenuId.REMOVE.getId(), Menu.NONE, "Remove");
113   }
114 
115   @Override
onContextItemSelected(MenuItem item)116   public boolean onContextItemSelected(MenuItem item) {
117     AdapterView.AdapterContextMenuInfo info;
118     try {
119       info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
120     } catch (ClassCastException e) {
121       Log.e("Bad menuInfo", e);
122       return false;
123     }
124 
125     Trigger trigger = mAdapter.getItem(info.position);
126     if (trigger == null) {
127       Log.v("No trigger selected.");
128       return false;
129     }
130 
131     if (item.getItemId() == ContextMenuId.REMOVE.getId()) {
132       mTriggerRepository.remove(trigger);
133     }
134     return true;
135   }
136 
137   @Override
onListItemClick(ListView l, View v, int position, long id)138   public void onListItemClick(ListView l, View v, int position, long id) {
139     mAdapter.notifyDataSetInvalidated();
140   }
141 
142   private class ScriptTriggerListObserver implements TriggerRepositoryObserver {
143 
144     @Override
onPut(Trigger trigger)145     public void onPut(Trigger trigger) {
146       mTriggers.add((ScriptTrigger) trigger);
147       mAdapter.notifyDataSetInvalidated();
148     }
149 
150     @Override
onRemove(Trigger trigger)151     public void onRemove(Trigger trigger) {
152       mTriggers.remove(trigger);
153       mAdapter.notifyDataSetInvalidated();
154     }
155   }
156 
157   private class ScriptTriggerAdapter extends BaseAdapter {
158 
159     @Override
getCount()160     public int getCount() {
161       return mTriggers.size();
162     }
163 
164     @Override
getItem(int position)165     public Trigger getItem(int position) {
166       return mTriggers.get(position);
167     }
168 
169     @Override
getItemId(int position)170     public long getItemId(int position) {
171       return position;
172     }
173 
174     @Override
getView(final int position, View convertView, ViewGroup parent)175     public View getView(final int position, View convertView, ViewGroup parent) {
176       ScriptTrigger trigger = mTriggers.get(position);
177       TextView textView = new TextView(TriggerManager.this);
178       textView.setText(trigger.getEventName() + " " + trigger.getScript().getName());
179       return textView;
180     }
181   }
182 
183   @Override
onActivityResult(int requestCode, int resultCode, Intent data)184   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
185     if (resultCode == RESULT_OK) {
186       final File script = new File(data.getStringExtra(Constants.EXTRA_SCRIPT_PATH));
187       if (requestCode == MenuId.ADD.getId()) {
188         Map<String, MethodDescriptor> eventMethodDescriptors =
189             FacadeConfiguration.collectStartEventMethodDescriptors();
190         final List<String> eventNames = Lists.newArrayList(eventMethodDescriptors.keySet());
191         Collections.sort(eventNames);
192         AlertDialog.Builder builder = new AlertDialog.Builder(this);
193         builder.setItems(eventNames.toArray(new CharSequence[eventNames.size()]),
194             new OnClickListener() {
195               @Override
196               public void onClick(DialogInterface dialog, int position) {
197                 mTriggerRepository.put(new ScriptTrigger(eventNames.get(position), script));
198               }
199             });
200         builder.show();
201       }
202     }
203   }
204 
clickCancel(View v)205   public void clickCancel(View v) {
206     for (Trigger t : mTriggerRepository.getAllTriggers().values()) {
207       mTriggerRepository.remove(t);
208     }
209   }
210 }
211