1ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey/* 2ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project 3ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * 4ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * you may not use this file except in compliance with the License. 6ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * You may obtain a copy of the License at 7ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * 8ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * 10ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 11ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * See the License for the specific language governing permissions and 14ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * limitations under the License. 15ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey */ 16ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey 17ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeypackage com.android.terminal; 18ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey 1900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport static com.android.terminal.Terminal.TAG; 2000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 21ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeyimport android.app.Activity; 22de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.content.ComponentName; 23de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.content.Context; 24de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.content.Intent; 25de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.content.ServiceConnection; 26ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeyimport android.os.Bundle; 27de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.os.IBinder; 2800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport android.os.Parcelable; 29de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.support.v4.view.PagerAdapter; 30de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.support.v4.view.PagerTitleStrip; 31de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.support.v4.view.ViewPager; 32ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeyimport android.util.Log; 3300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport android.util.SparseArray; 34de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.view.Menu; 35de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.view.MenuItem; 36de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.view.View; 37de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkeyimport android.view.ViewGroup; 38ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey 39de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey/** 40de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey * Activity that displays all {@link Terminal} instances running in a bound 41de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey * {@link TerminalService}. 42de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey */ 43ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeypublic class TerminalActivity extends Activity { 44ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey 45de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey private TerminalService mService; 46de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 47de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey private ViewPager mPager; 48de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey private PagerTitleStrip mTitles; 49de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 50de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey private final ServiceConnection mServiceConn = new ServiceConnection() { 51de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 52de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public void onServiceConnected(ComponentName name, IBinder service) { 53de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mService = ((TerminalService.ServiceBinder) service).getService(); 54de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 55de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey final int size = mService.getTerminals().size(); 56de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey Log.d(TAG, "Bound to service with " + size + " active terminals"); 57de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 58de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey // Give ourselves at least one terminal session 59de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey if (size == 0) { 60de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mService.createTerminal(); 61de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 62de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 63de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey // Bind UI to known terminals 64de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mTermAdapter.notifyDataSetChanged(); 6500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey invalidateOptionsMenu(); 66de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 67de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 68de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 69de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public void onServiceDisconnected(ComponentName name) { 70de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mService = null; 71de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey throw new RuntimeException("Service in same process disconnected?"); 72de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 73de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey }; 74de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 75de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey private final PagerAdapter mTermAdapter = new PagerAdapter() { 7600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private SparseArray<SparseArray<Parcelable>> 7700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mSavedState = new SparseArray<SparseArray<Parcelable>>(); 7800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 79de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 80de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public int getCount() { 81de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey if (mService != null) { 82de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return mService.getTerminals().size(); 83de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } else { 84de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return 0; 85de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 86de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 87de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 88de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 89de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public Object instantiateItem(ViewGroup container, int position) { 90de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey final TerminalView view = new TerminalView(container.getContext()); 9100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey view.setId(android.R.id.list); 9200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 9300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final Terminal term = mService.getTerminals().valueAt(position); 94de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey view.setTerminal(term); 9500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 9600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final SparseArray<Parcelable> state = mSavedState.get(term.key); 9700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (state != null) { 9800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey view.restoreHierarchyState(state); 9900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 10000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 101de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey container.addView(view); 1028dc54499bf4afccb60cd3500b03767cab9e2ab43Tom Marshall view.requestFocus(); 103de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return view; 104de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 105de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 106de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 107de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public void destroyItem(ViewGroup container, int position, Object object) { 108de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey final TerminalView view = (TerminalView) object; 10900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 11000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final int key = view.getTerminal().key; 11100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey SparseArray<Parcelable> state = mSavedState.get(key); 11200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (state == null) { 11300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey state = new SparseArray<Parcelable>(); 11400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mSavedState.put(key, state); 11500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 11600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey view.saveHierarchyState(state); 11700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 118de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey view.setTerminal(null); 119de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey container.removeView(view); 120de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 121de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 122de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 123de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public int getItemPosition(Object object) { 12400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final TerminalView view = (TerminalView) object; 12500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final int key = view.getTerminal().key; 12600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final int index = mService.getTerminals().indexOfKey(key); 127de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey if (index == -1) { 128de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return POSITION_NONE; 129de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } else { 130de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return index; 131de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 132de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 133de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 134de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 135de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public boolean isViewFromObject(View view, Object object) { 136de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return view == object; 137de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 138de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 139de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 140de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public CharSequence getPageTitle(int position) { 14100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return mService.getTerminals().valueAt(position).getTitle(); 142de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 143de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey }; 144de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 145ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey @Override 146ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey protected void onCreate(Bundle savedInstanceState) { 147ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey super.onCreate(savedInstanceState); 148ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey 149de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey setContentView(R.layout.activity); 150de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 151de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mPager = (ViewPager) findViewById(R.id.pager); 152de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mTitles = (PagerTitleStrip) findViewById(R.id.titles); 153de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 154de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mPager.setAdapter(mTermAdapter); 155de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 156de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 157de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 158de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey protected void onStart() { 159de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey super.onStart(); 160de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey bindService( 161de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey new Intent(this, TerminalService.class), mServiceConn, Context.BIND_AUTO_CREATE); 162de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 163479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey 164de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 165de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey protected void onStop() { 166de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey super.onStop(); 167de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey unbindService(mServiceConn); 168de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 169410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 170de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 171de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public boolean onCreateOptionsMenu(Menu menu) { 172de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey getMenuInflater().inflate(R.menu.activity, menu); 173de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return true; 174de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 175410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 176de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey @Override 17700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public boolean onPrepareOptionsMenu(Menu menu) { 17800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey super.onPrepareOptionsMenu(menu); 17900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey menu.findItem(R.id.menu_close_tab).setEnabled(mTermAdapter.getCount() > 0); 18000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return true; 18100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 18200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 18300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 184de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public boolean onOptionsItemSelected(MenuItem item) { 185de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey switch (item.getItemId()) { 186de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey case R.id.menu_new_tab: { 187de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mService.createTerminal(); 188de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mTermAdapter.notifyDataSetChanged(); 18900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey invalidateOptionsMenu(); 190de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey final int index = mService.getTerminals().size() - 1; 191de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mPager.setCurrentItem(index, true); 192de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return true; 193de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 194de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey case R.id.menu_close_tab: { 195de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey final int index = mPager.getCurrentItem(); 19600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final int key = mService.getTerminals().keyAt(index); 19700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mService.destroyTerminal(key); 198de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey mTermAdapter.notifyDataSetChanged(); 19900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey invalidateOptionsMenu(); 200de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return true; 201de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 202de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 203de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey return false; 204ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey } 205ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey} 206