Home | History | Annotate | Download | only in terminal
      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
    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