InCallActivity.java revision 7ac6cb331919db2a3a8985e4cb3299b309d9012a
1/*
2 * Copyright (C) 2006 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.incallui;
18
19import android.app.Activity;
20import android.app.Fragment;
21import android.content.Intent;
22import android.os.Bundle;
23import android.util.Log;
24import android.view.KeyEvent;
25import android.view.View;
26import android.view.Window;
27import android.view.WindowManager;
28import android.widget.Toast;
29
30/**
31 * Phone app "in call" screen.
32 */
33public class InCallActivity extends Activity {
34    private static final String TAG = InCallActivity.class.getSimpleName();
35    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
36    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
37
38    private CallButtonFragment mCallButtonFragment;
39    private CallCardFragment mCallCardFragment;
40    private AnswerFragment mAnswerFragment;
41
42    @Override
43    protected void onCreate(Bundle icicle) {
44        logD("onCreate()...  this = " + this);
45
46        super.onCreate(icicle);
47
48        // set this flag so this activity will stay in front of the keyguard
49        // Have the WindowManager filter out touch events that are "too fat".
50        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
51                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
52                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
53                | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES);
54
55        requestWindowFeature(Window.FEATURE_NO_TITLE);
56
57        // Inflate everything in incall_screen.xml and add it to the screen.
58        setContentView(R.layout.incall_screen);
59
60        initializeInCall();
61
62        logD("onCreate(): exit");
63    }
64
65    @Override
66    protected void onResume() {
67        logD("onResume()...");
68        super.onResume();
69    }
70
71    // onPause is guaranteed to be called when the InCallActivity goes
72    // in the background.
73    @Override
74    protected void onPause() {
75        logD("onPause()...");
76        super.onPause();
77    }
78
79    @Override
80    protected void onStop() {
81        logD("onStop()...");
82        super.onStop();
83    }
84
85    @Override
86    protected void onDestroy() {
87        logD("onDestroy()...  this = " + this);
88        super.onDestroy();
89    }
90
91    /**
92     * Dismisses the in-call screen.
93     *
94     * We never *really* finish() the InCallActivity, since we don't want to get destroyed and then
95     * have to be re-created from scratch for the next call.  Instead, we just move ourselves to the
96     * back of the activity stack.
97     *
98     * This also means that we'll no longer be reachable via the BACK button (since moveTaskToBack()
99     * puts us behind the Home app, but the home app doesn't allow the BACK key to move you any
100     * farther down in the history stack.)
101     *
102     * (Since the Phone app itself is never killed, this basically means that we'll keep a single
103     * InCallActivity instance around for the entire uptime of the device.  This noticeably improves
104     * the UI responsiveness for incoming calls.)
105     */
106    @Override
107    public void finish() {
108        logD("finish()...");
109        super.finish();
110
111        // TODO(klp): Actually finish the activity for now.  Revisit performance implications of
112        // this before launch.
113        // moveTaskToBack(true);
114    }
115
116    @Override
117    protected void onNewIntent(Intent intent) {
118        logD("onNewIntent: intent = " + intent);
119
120        // We're being re-launched with a new Intent.  Since it's possible for a
121        // single InCallActivity instance to persist indefinitely (even if we
122        // finish() ourselves), this sequence can potentially happen any time
123        // the InCallActivity needs to be displayed.
124
125        // Stash away the new intent so that we can get it in the future
126        // by calling getIntent().  (Otherwise getIntent() will return the
127        // original Intent from when we first got created!)
128        setIntent(intent);
129
130        // Activities are always paused before receiving a new intent, so
131        // we can count on our onResume() method being called next.
132
133        // Just like in onCreate(), handle the intent.
134        //TODO(klp): handle intent
135    }
136
137    @Override
138    public void onBackPressed() {
139        // TODO(klp): implement
140
141        // Nothing special to do.  Fall back to the default behavior.
142        super.onBackPressed();
143    }
144
145    @Override
146    public boolean onKeyDown(int keyCode, KeyEvent event) {
147        switch (keyCode) {
148            case KeyEvent.KEYCODE_CALL:
149                // TODO(klp): handle call key
150                // Always consume CALL to be sure the PhoneWindow won't do anything with it
151                return true;
152
153            // Note there's no KeyEvent.KEYCODE_ENDCALL case here.
154            // The standard system-wide handling of the ENDCALL key
155            // (see PhoneWindowManager's handling of KEYCODE_ENDCALL)
156            // already implements exactly what the UI spec wants,
157            // namely (1) "hang up" if there's a current active call,
158            // or (2) "don't answer" if there's a current ringing call.
159
160            case KeyEvent.KEYCODE_CAMERA:
161                // Disable the CAMERA button while in-call since it's too
162                // easy to press accidentally.
163                return true;
164
165            case KeyEvent.KEYCODE_VOLUME_UP:
166            case KeyEvent.KEYCODE_VOLUME_DOWN:
167            case KeyEvent.KEYCODE_VOLUME_MUTE:
168                // Not sure if needed. If so, silence ringer.
169                break;
170
171            case KeyEvent.KEYCODE_MUTE:
172                toast("mute");
173                return true;
174
175            // Various testing/debugging features, enabled ONLY when VERBOSE == true.
176            case KeyEvent.KEYCODE_SLASH:
177                if (VERBOSE) {
178                    Log.v(TAG, "----------- InCallActivity View dump --------------");
179                    // Dump starting from the top-level view of the entire activity:
180                    Window w = this.getWindow();
181                    View decorView = w.getDecorView();
182                    decorView.debug();
183                    return true;
184                }
185                break;
186            case KeyEvent.KEYCODE_EQUALS:
187                // TODO(klp): Dump phone state?
188                break;
189        }
190
191        // TODO(klp): handle dialer key down
192
193        return super.onKeyDown(keyCode, event);
194    }
195
196    private void initializeInCall() {
197        // TODO(klp): Make sure that this doesn't need to move back to onResume() since they are
198        // statically added fragments.
199        if (mCallButtonFragment == null) {
200            mCallButtonFragment = (CallButtonFragment) getFragmentManager()
201                    .findFragmentById(R.id.callButtonFragment);
202        }
203
204        if (mCallCardFragment == null) {
205            mCallCardFragment = (CallCardFragment) getFragmentManager()
206                    .findFragmentById(R.id.callCardFragment);
207        }
208
209        if (mAnswerFragment == null) {
210            mAnswerFragment = (AnswerFragment) getFragmentManager()
211                    .findFragmentById(R.id.answerFragment);
212        }
213
214        setUpPresenters();
215    }
216
217    private void setUpPresenters() {
218        InCallPresenter mainPresenter = InCallPresenter.getInstance();
219
220        mainPresenter.addListener(mCallButtonFragment.getPresenter());
221        mainPresenter.addListener(mCallCardFragment.getPresenter());
222        mainPresenter.addListener(mAnswerFragment.getPresenter());
223
224        // setting activity should be last thing in setup process
225        mainPresenter.setActivity(this);
226    }
227
228    private void toast(String text) {
229        final Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
230
231        toast.show();
232    }
233
234    private void logD(String msg) {
235        if (DEBUG) {
236            Log.d(TAG, msg);
237        }
238    }
239}
240