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.facade.ui; 18 19 import android.R; 20 import android.os.Handler; 21 import android.view.KeyEvent; 22 import android.view.Menu; 23 import android.view.View; 24 import android.view.View.OnClickListener; 25 import android.view.ViewGroup.LayoutParams; 26 import android.widget.AdapterView; 27 import android.widget.AdapterView.OnItemClickListener; 28 import android.widget.Button; 29 import android.widget.LinearLayout; 30 import android.widget.TextView; 31 32 import com.googlecode.android_scripting.facade.EventFacade; 33 import com.googlecode.android_scripting.future.FutureActivityTask; 34 35 import java.io.StringReader; 36 import java.util.HashMap; 37 import java.util.List; 38 import java.util.Map; 39 import java.util.concurrent.CountDownLatch; 40 41 import org.json.JSONArray; 42 import org.xmlpull.v1.XmlPullParser; 43 44 public class FullScreenTask extends FutureActivityTask<Object> implements OnClickListener, 45 OnItemClickListener { 46 private EventFacade mEventFacade; 47 private UiFacade mUiFacade; 48 public View mView = null; 49 protected ViewInflater mInflater = new ViewInflater(); 50 protected String mLayout; 51 protected final CountDownLatch mShowLatch = new CountDownLatch(1); 52 protected Handler mHandler = null; 53 private List<Integer> mOverrideKeys; 54 protected String mTitle; 55 56 public FullScreenTask(String layout, String title) { 57 super(); 58 mLayout = layout; 59 if (title != null) { 60 mTitle = title; 61 } else { 62 mTitle = "SL4a"; 63 } 64 } 65 66 @Override 67 public void onCreate() { 68 // super.onCreate(); 69 if (mHandler == null) { 70 mHandler = new Handler(); 71 } 72 mInflater.getErrors().clear(); 73 try { 74 if (mView == null) { 75 StringReader sr = new StringReader(mLayout); 76 XmlPullParser xml = ViewInflater.getXml(sr); 77 mView = mInflater.inflate(getActivity(), xml); 78 } 79 } catch (Exception e) { 80 mInflater.getErrors().add(e.toString()); 81 mView = defaultView(); 82 mInflater.setIdList(R.id.class); 83 } 84 getActivity().setContentView(mView); 85 getActivity().setTitle(mTitle); 86 mInflater.setClickListener(mView, this, this); 87 mShowLatch.countDown(); 88 } 89 90 @Override 91 public void onDestroy() { 92 mEventFacade.postEvent("screen", "destroy"); 93 super.onDestroy(); 94 } 95 96 /** default view in case of errors */ 97 protected View defaultView() { 98 LinearLayout result = new LinearLayout(getActivity()); 99 result.setOrientation(LinearLayout.VERTICAL); 100 TextView text = new TextView(getActivity()); 101 text.setText("Sample Layout"); 102 result.addView(text, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 103 Button b = new Button(getActivity()); 104 b.setText("OK"); 105 result.addView(b, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 106 return result; 107 } 108 109 public EventFacade getEventFacade() { 110 return mEventFacade; 111 } 112 113 public void setEventFacade(EventFacade eventFacade) { 114 mEventFacade = eventFacade; 115 } 116 117 public void setUiFacade(UiFacade uiFacade) { 118 mUiFacade = uiFacade; 119 } 120 121 public CountDownLatch getShowLatch() { 122 return mShowLatch; 123 } 124 125 public Map<String, Map<String, String>> getViewAsMap() { 126 return mInflater.getViewAsMap(mView); 127 } 128 129 private View getViewByName(String idName) { 130 View result = null; 131 int id = mInflater.getId(idName); 132 if (id != 0) { 133 result = mView.findViewById(id); 134 } 135 return result; 136 } 137 138 public Map<String, String> getViewDetail(String idName) { 139 Map<String, String> result = new HashMap<String, String>(); 140 result.put("error", "id not found (" + idName + ")"); 141 View v = getViewByName(idName); 142 if (v != null) { 143 result = mInflater.getViewInfo(v); 144 } 145 return result; 146 } 147 148 public String setViewProperty(String idName, String property, String value) { 149 View v = getViewByName(idName); 150 mInflater.getErrors().clear(); 151 if (v != null) { 152 SetProperty p = new SetProperty(v, property, value); 153 mHandler.post(p); 154 try { 155 p.mLatch.await(); 156 } catch (InterruptedException e) { 157 mInflater.getErrors().add(e.toString()); 158 } 159 } else { 160 return "View " + idName + " not found."; 161 } 162 if (mInflater.getErrors().size() == 0) { 163 return "OK"; 164 } 165 return mInflater.getErrors().get(0); 166 } 167 168 public String setList(String id, JSONArray items) { 169 View v = getViewByName(id); 170 mInflater.getErrors().clear(); 171 if (v != null) { 172 SetList p = new SetList(v, items); 173 mHandler.post(p); 174 try { 175 p.mLatch.await(); 176 } catch (InterruptedException e) { 177 mInflater.getErrors().add(e.toString()); 178 } 179 } else { 180 return "View " + id + " not found."; 181 } 182 if (mInflater.getErrors().size() == 0) { 183 return "OK"; 184 } 185 return mInflater.getErrors().get(0); 186 } 187 188 @Override 189 public void onClick(View view) { 190 mEventFacade.postEvent("click", mInflater.getViewInfo(view)); 191 } 192 193 public void loadLayout(String layout) { 194 ViewInflater inflater = new ViewInflater(); 195 View view; 196 StringReader sr = new StringReader(layout); 197 try { 198 XmlPullParser xml = ViewInflater.getXml(sr); 199 view = inflater.inflate(getActivity(), xml); 200 mView = view; 201 mInflater = inflater; 202 getActivity().setContentView(mView); 203 mInflater.setClickListener(mView, this, this); 204 mLayout = layout; 205 mView.invalidate(); 206 } catch (Exception e) { 207 mInflater.getErrors().add(e.toString()); 208 } 209 } 210 211 private class SetProperty implements Runnable { 212 View mView; 213 String mProperty; 214 String mValue; 215 CountDownLatch mLatch = new CountDownLatch(1); 216 217 SetProperty(View view, String property, String value) { 218 mView = view; 219 mProperty = property; 220 mValue = value; 221 } 222 223 @Override 224 public void run() { 225 // TODO Auto-generated method stub 226 mInflater.setProperty(mView, mProperty, mValue); 227 mView.invalidate(); 228 mLatch.countDown(); 229 } 230 } 231 232 private class SetList implements Runnable { 233 View mView; 234 JSONArray mItems; 235 CountDownLatch mLatch = new CountDownLatch(1); 236 237 SetList(View view, JSONArray items) { 238 mView = view; 239 mItems = items; 240 mLatch.countDown(); 241 } 242 243 @Override 244 public void run() { 245 mInflater.setListAdapter(mView, mItems); 246 mView.invalidate(); 247 } 248 } 249 250 private class SetLayout implements Runnable { 251 String mLayout; 252 CountDownLatch mLatch = new CountDownLatch(1); 253 254 SetLayout(String layout) { 255 mLayout = layout; 256 } 257 258 @Override 259 public void run() { 260 loadLayout(mLayout); 261 mLatch.countDown(); 262 } 263 } 264 265 private class SetTitle implements Runnable { 266 String mSetTitle; 267 CountDownLatch mLatch = new CountDownLatch(1); 268 269 SetTitle(String title) { 270 mSetTitle = title; 271 } 272 273 @Override 274 public void run() { 275 mTitle = mSetTitle; 276 getActivity().setTitle(mSetTitle); 277 mLatch.countDown(); 278 } 279 } 280 281 @Override 282 public boolean onKeyDown(int keyCode, KeyEvent event) { 283 Map<String, String> data = new HashMap<String, String>(); 284 data.put("key", String.valueOf(keyCode)); 285 data.put("action", String.valueOf(event.getAction())); 286 mEventFacade.postEvent("key", data); 287 boolean overrideKey = 288 (keyCode == KeyEvent.KEYCODE_BACK) 289 || (mOverrideKeys == null ? false : mOverrideKeys.contains(keyCode)); 290 return overrideKey; 291 } 292 293 @Override 294 public boolean onPrepareOptionsMenu(Menu menu) { 295 return mUiFacade.onPrepareOptionsMenu(menu); 296 } 297 298 @Override 299 public void onItemClick(AdapterView<?> aview, View aitem, int position, long id) { 300 Map<String, String> data = mInflater.getViewInfo(aview); 301 data.put("position", String.valueOf(position)); 302 mEventFacade.postEvent("itemclick", data); 303 } 304 305 public void setOverrideKeys(List<Integer> overrideKeys) { 306 mOverrideKeys = overrideKeys; 307 } 308 309 // Used to hot-switch screens. 310 public void setLayout(String layout) { 311 SetLayout p = new SetLayout(layout); 312 mHandler.post(p); 313 try { 314 p.mLatch.await(); 315 } catch (InterruptedException e) { 316 mInflater.getErrors().add(e.toString()); 317 } 318 } 319 320 public void setTitle(String title) { 321 SetTitle p = new SetTitle(title); 322 mHandler.post(p); 323 try { 324 p.mLatch.await(); 325 } catch (InterruptedException e) { 326 mInflater.getErrors().add(e.toString()); 327 } 328 } 329 330 } 331