1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.terminal;
18 
19 import static com.android.terminal.Terminal.TAG;
20 
21 import android.app.Activity;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.ServiceConnection;
26 import android.os.Bundle;
27 import android.os.IBinder;
28 import android.os.Parcelable;
29 import android.support.v4.view.PagerAdapter;
30 import android.support.v4.view.PagerTitleStrip;
31 import android.support.v4.view.ViewPager;
32 import android.util.Log;
33 import android.util.SparseArray;
34 import android.view.Menu;
35 import android.view.MenuItem;
36 import android.view.View;
37 import android.view.ViewGroup;
38 
39 /**
40  * Activity that displays all {@link Terminal} instances running in a bound
41  * {@link TerminalService}.
42  */
43 public class TerminalActivity extends Activity {
44 
45     private TerminalService mService;
46 
47     private ViewPager mPager;
48     private PagerTitleStrip mTitles;
49 
50     private final ServiceConnection mServiceConn = new ServiceConnection() {
51         @Override
52         public void onServiceConnected(ComponentName name, IBinder service) {
53             mService = ((TerminalService.ServiceBinder) service).getService();
54 
55             final int size = mService.getTerminals().size();
56             Log.d(TAG, "Bound to service with " + size + " active terminals");
57 
58             // Give ourselves at least one terminal session
59             if (size == 0) {
60                 mService.createTerminal();
61             }
62 
63             // Bind UI to known terminals
64             mTermAdapter.notifyDataSetChanged();
65             invalidateOptionsMenu();
66         }
67 
68         @Override
69         public void onServiceDisconnected(ComponentName name) {
70             mService = null;
71             throw new RuntimeException("Service in same process disconnected?");
72         }
73     };
74 
75     private final PagerAdapter mTermAdapter = new PagerAdapter() {
76         private SparseArray<SparseArray<Parcelable>>
77                 mSavedState = new SparseArray<SparseArray<Parcelable>>();
78 
79         @Override
80         public int getCount() {
81             if (mService != null) {
82                 return mService.getTerminals().size();
83             } else {
84                 return 0;
85             }
86         }
87 
88         @Override
89         public Object instantiateItem(ViewGroup container, int position) {
90             final TerminalView view = new TerminalView(container.getContext());
91             view.setId(android.R.id.list);
92 
93             final Terminal term = mService.getTerminals().valueAt(position);
94             view.setTerminal(term);
95 
96             final SparseArray<Parcelable> state = mSavedState.get(term.key);
97             if (state != null) {
98                 view.restoreHierarchyState(state);
99             }
100 
101             container.addView(view);
102             view.requestFocus();
103             return view;
104         }
105 
106         @Override
107         public void destroyItem(ViewGroup container, int position, Object object) {
108             final TerminalView view = (TerminalView) object;
109 
110             final int key = view.getTerminal().key;
111             SparseArray<Parcelable> state = mSavedState.get(key);
112             if (state == null) {
113                 state = new SparseArray<Parcelable>();
114                 mSavedState.put(key, state);
115             }
116             view.saveHierarchyState(state);
117 
118             view.setTerminal(null);
119             container.removeView(view);
120         }
121 
122         @Override
123         public int getItemPosition(Object object) {
124             final TerminalView view = (TerminalView) object;
125             final int key = view.getTerminal().key;
126             final int index = mService.getTerminals().indexOfKey(key);
127             if (index == -1) {
128                 return POSITION_NONE;
129             } else {
130                 return index;
131             }
132         }
133 
134         @Override
135         public boolean isViewFromObject(View view, Object object) {
136             return view == object;
137         }
138 
139         @Override
140         public CharSequence getPageTitle(int position) {
141             return mService.getTerminals().valueAt(position).getTitle();
142         }
143     };
144 
145     @Override
onCreate(Bundle savedInstanceState)146     protected void onCreate(Bundle savedInstanceState) {
147         super.onCreate(savedInstanceState);
148 
149         setContentView(R.layout.activity);
150 
151         mPager = (ViewPager) findViewById(R.id.pager);
152         mTitles = (PagerTitleStrip) findViewById(R.id.titles);
153 
154         mPager.setAdapter(mTermAdapter);
155     }
156 
157     @Override
onStart()158     protected void onStart() {
159         super.onStart();
160         bindService(
161                 new Intent(this, TerminalService.class), mServiceConn, Context.BIND_AUTO_CREATE);
162     }
163 
164     @Override
onStop()165     protected void onStop() {
166         super.onStop();
167         unbindService(mServiceConn);
168     }
169 
170     @Override
onCreateOptionsMenu(Menu menu)171     public boolean onCreateOptionsMenu(Menu menu) {
172         getMenuInflater().inflate(R.menu.activity, menu);
173         return true;
174     }
175 
176     @Override
onPrepareOptionsMenu(Menu menu)177     public boolean onPrepareOptionsMenu(Menu menu) {
178         super.onPrepareOptionsMenu(menu);
179         menu.findItem(R.id.menu_close_tab).setEnabled(mTermAdapter.getCount() > 0);
180         return true;
181     }
182 
183     @Override
onOptionsItemSelected(MenuItem item)184     public boolean onOptionsItemSelected(MenuItem item) {
185         switch (item.getItemId()) {
186             case R.id.menu_new_tab: {
187                 mService.createTerminal();
188                 mTermAdapter.notifyDataSetChanged();
189                 invalidateOptionsMenu();
190                 final int index = mService.getTerminals().size() - 1;
191                 mPager.setCurrentItem(index, true);
192                 return true;
193             }
194             case R.id.menu_close_tab: {
195                 final int index = mPager.getCurrentItem();
196                 final int key = mService.getTerminals().keyAt(index);
197                 mService.destroyTerminal(key);
198                 mTermAdapter.notifyDataSetChanged();
199                 invalidateOptionsMenu();
200                 return true;
201             }
202         }
203         return false;
204     }
205 }
206