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
17package com.android.terminal;
18
19import static com.android.terminal.Terminal.TAG;
20
21import android.app.Activity;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.ServiceConnection;
26import android.os.Bundle;
27import android.os.IBinder;
28import android.os.Parcelable;
29import android.support.v4.view.PagerAdapter;
30import android.support.v4.view.PagerTitleStrip;
31import android.support.v4.view.ViewPager;
32import android.util.Log;
33import android.util.SparseArray;
34import android.view.Menu;
35import android.view.MenuItem;
36import android.view.View;
37import android.view.ViewGroup;
38
39/**
40 * Activity that displays all {@link Terminal} instances running in a bound
41 * {@link TerminalService}.
42 */
43public 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
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
158    protected void onStart() {
159        super.onStart();
160        bindService(
161                new Intent(this, TerminalService.class), mServiceConn, Context.BIND_AUTO_CREATE);
162    }
163
164    @Override
165    protected void onStop() {
166        super.onStop();
167        unbindService(mServiceConn);
168    }
169
170    @Override
171    public boolean onCreateOptionsMenu(Menu menu) {
172        getMenuInflater().inflate(R.menu.activity, menu);
173        return true;
174    }
175
176    @Override
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
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