Merge branch 'gingerbread' into gingerbread-release
This commit is contained in:
@@ -160,6 +160,7 @@ development/samples/MultiResolution samples/${PLATFORM_NAME}/MultiResol
|
||||
development/samples/NotePad samples/${PLATFORM_NAME}/NotePad
|
||||
development/samples/SampleSyncAdapter samples/${PLATFORM_NAME}/SampleSyncAdapter
|
||||
development/samples/SearchableDictionary samples/${PLATFORM_NAME}/SearchableDictionary
|
||||
development/samples/SipDemo samples/${PLATFORM_NAME}/SipDemo
|
||||
development/samples/SkeletonApp samples/${PLATFORM_NAME}/SkeletonApp
|
||||
development/samples/Snake samples/${PLATFORM_NAME}/Snake
|
||||
development/samples/SoftKeyboard samples/${PLATFORM_NAME}/SoftKeyboard
|
||||
|
||||
54
samples/Alarm/AndroidManifest.xml
Normal file
54
samples/Alarm/AndroidManifest.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Declares the contents of this Android application. The xmlns:android
|
||||
attribute brings in the Android platform namespace, and the
|
||||
"package" attribute provides a unique name for the application.
|
||||
If you use this file as a template in your own application, you must change
|
||||
the package name from "com.example.android" to one that you own or have
|
||||
control over.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.newalarm"
|
||||
android:versionCode="2"
|
||||
android:versionName="2.0">
|
||||
<!--
|
||||
Declares the application, its icon, and its visible label
|
||||
-->
|
||||
<application
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name">
|
||||
<!--
|
||||
Declares the activity's class name and visible label. The leading "." indicates
|
||||
that the name should be preceded by the application's Android package name.
|
||||
-->
|
||||
<activity
|
||||
android:name=".AlarmActivity"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service
|
||||
android:name=".AlarmService"
|
||||
android:label="@string/alarm_service"
|
||||
android:process="com.example.android.newalarm">
|
||||
</service>
|
||||
</application>
|
||||
<uses-sdk android:targetSdkVersion="4" android:minSdkVersion="3"/>
|
||||
</manifest>
|
||||
29
samples/Alarm/_index.html
Normal file
29
samples/Alarm/_index.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<p>
|
||||
This sample is a revised version of the AlarmService functionality included in the
|
||||
ApiDemos sample application. It is used as the application under test
|
||||
for the <a href="../AlarmServiceTest/index.html">Alarm Service Test</a>
|
||||
sample test application.
|
||||
</p>
|
||||
<p>
|
||||
This application demonstrates a simple Android service that is started when needed by
|
||||
<code>Context.startService(Intent)</code> and stops itself when its work is done. You can
|
||||
use this type of service to move long-running or periodic tasks into the background. For
|
||||
example, you could use this type of service to perform data synchronization.
|
||||
</p>
|
||||
<p>
|
||||
In the sample, the service simply runs for 15 seconds and then stops itself. The wait is
|
||||
implemented in a separate thread that uses a thread-safe object. This illustrates how to
|
||||
set up a service that runs multiple threads that depend on one or more objects that must be
|
||||
made thread-safe.
|
||||
</p>
|
||||
<p>
|
||||
The application also contains the <code>AlarmActivity</code> activity that is a client of the
|
||||
service. You use the activity to control when the service starts and stops. By default, the
|
||||
activity fires off the service every thirty seconds. In effect, the service starts after
|
||||
thirty seconds, runs for 15 seconds, stops, and then runs again automatically in another
|
||||
15 seconds. You also use the client to stop this cycle.
|
||||
</p>
|
||||
<p>
|
||||
The test application <a href="tests/index.html">AlarmServiceTest</a>
|
||||
shows you how to set up a test of this service.
|
||||
</p>
|
||||
BIN
samples/Alarm/res/drawable/icon.png
Normal file
BIN
samples/Alarm/res/drawable/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
BIN
samples/Alarm/res/drawable/stat_sample.png
Executable file
BIN
samples/Alarm/res/drawable/stat_sample.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 364 B |
44
samples/Alarm/res/layout/main.xml
Normal file
44
samples/Alarm/res/layout/main.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- Demonstrates starting and stopping a local service.
|
||||
See corresponding Java code com.android.sdk.app.LocalSerice.java. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:padding="4dip"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:paddingBottom="4dip"
|
||||
android:text="@string/alarm_service"/>
|
||||
<Button android:id="@+id/start_alarm"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/start_alarm_service">
|
||||
<requestFocus />
|
||||
</Button>
|
||||
|
||||
<Button android:id="@+id/stop_alarm"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/stop_alarm_service" />
|
||||
</LinearLayout>
|
||||
|
||||
29
samples/Alarm/res/values/strings.xml
Normal file
29
samples/Alarm/res/values/strings.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<string name="app_name">Alarm</string>
|
||||
<string name="alarm_service">
|
||||
This shows how to schedule a repeating alarm that starts a service.</string>
|
||||
<string name="start_alarm_service">Start Alarm Service</string>
|
||||
<string name="stop_alarm_service">Stop Alarm Service</string>
|
||||
<string name="repeating_started">
|
||||
Repeating timer started. Starts AlarmService every 30 seconds.</string>
|
||||
<string name="alarm_service_started">The sample service is running.</string>
|
||||
<string name="alarm_service_label">Sample Alarm Service</string>
|
||||
<string name="alarm_service_finished">The sample service is no longer running.</string>
|
||||
<string name="repeating_stopped">
|
||||
Repeating timer stopped. AlarmService will no longer be started.</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.newalarm;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* This is the activity that controls AlarmService.
|
||||
* <p>
|
||||
* When the user clicks the "Start Alarm Service" button, it triggers a repeating countdown
|
||||
* timer. Every thirty seconds, the timer starts AlarmService, which then runs for 15 seconds
|
||||
* and shuts itself down.
|
||||
* </p>
|
||||
* <p>
|
||||
* When the user clicks the "Stop Alarm Service" button, it stops the countdown timer.
|
||||
* </p>
|
||||
*/
|
||||
|
||||
public class AlarmActivity extends Activity {
|
||||
// 30 seconds in milliseconds
|
||||
private static final long THIRTY_SECONDS_MILLIS = 30 * 1000;
|
||||
|
||||
// An intent for AlarmService, to trigger it as if the Activity called startService().
|
||||
private PendingIntent mAlarmSender;
|
||||
|
||||
// Contains a handle to the system alarm service
|
||||
private AlarmManager mAlarmManager;
|
||||
|
||||
/**
|
||||
* This method is called when Android starts the activity. It initializes the UI.
|
||||
* <p>
|
||||
* This method is automatically called when Android starts the Activity
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Create a PendingIntent to trigger a startService() for AlarmService
|
||||
mAlarmSender = PendingIntent.getService( // set up an intent for a call to a service
|
||||
AlarmActivity.this, // the current context
|
||||
0, // request code (not used)
|
||||
new Intent(AlarmActivity.this, AlarmService.class), // A new Service intent
|
||||
0 // flags (none are required for a service)
|
||||
);
|
||||
|
||||
// Creates the main view
|
||||
setContentView(R.layout.main);
|
||||
|
||||
// Finds the button that starts the repeating countdown timer
|
||||
Button button = (Button)findViewById(R.id.start_alarm);
|
||||
|
||||
// Sets the listener for the start button
|
||||
button.setOnClickListener(mStartAlarmListener);
|
||||
|
||||
// Finds the button that stops countdown timer
|
||||
button = (Button)findViewById(R.id.stop_alarm);
|
||||
|
||||
// Sets the listener for the stop button
|
||||
button.setOnClickListener(mStopAlarmListener);
|
||||
|
||||
// Gets the handle to the system alarm service
|
||||
mAlarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
|
||||
}
|
||||
|
||||
// Creates a new anonymous click listener for the start button. It starts the repeating
|
||||
// countdown timer.
|
||||
private OnClickListener mStartAlarmListener = new OnClickListener() {
|
||||
// Sets the callback for when the button is clicked
|
||||
public void onClick(View v) {
|
||||
|
||||
// Sets the time when the alarm will first go off
|
||||
// The Android AlarmManager uses this form of the current time.
|
||||
long firstAlarmTime = SystemClock.elapsedRealtime();
|
||||
|
||||
// Sets a repeating countdown timer that triggers AlarmService
|
||||
mAlarmManager.setRepeating(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP, // based on time since last wake up
|
||||
firstAlarmTime, // sends the first alarm immediately
|
||||
THIRTY_SECONDS_MILLIS, // repeats every thirty seconds
|
||||
mAlarmSender // when the alarm goes off, sends this Intent
|
||||
);
|
||||
|
||||
// Notifies the user that the repeating countdown timer has been started
|
||||
Toast.makeText(
|
||||
AlarmActivity.this, // the current context
|
||||
R.string.repeating_started, // the message to display
|
||||
Toast.LENGTH_LONG // how long to display the message
|
||||
).show(); // show the message on the screen
|
||||
}
|
||||
};
|
||||
|
||||
// Creates a new anonymous click listener for the stop button. It shuts off the repeating
|
||||
// countdown timer.
|
||||
private OnClickListener mStopAlarmListener = new OnClickListener() {
|
||||
// Sets the callback for when the button is clicked
|
||||
public void onClick(View v) {
|
||||
|
||||
// Cancels the repeating countdown timer
|
||||
mAlarmManager.cancel(mAlarmSender);
|
||||
|
||||
// Notifies the user that the repeating countdown timer has been stopped
|
||||
Toast.makeText(
|
||||
AlarmActivity.this, // the current context
|
||||
R.string.repeating_stopped, // the message to display
|
||||
Toast.LENGTH_LONG // how long to display the message
|
||||
).show(); // display the message
|
||||
}
|
||||
};
|
||||
}
|
||||
216
samples/Alarm/src/com/example/android/newalarm/AlarmService.java
Normal file
216
samples/Alarm/src/com/example/android/newalarm/AlarmService.java
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.newalarm;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This class implements a service. The service is started by AlarmActivity, which contains a
|
||||
* repeating countdown timer that sends a PendingIntent. The user starts and stops the timer with
|
||||
* buttons in the UI.
|
||||
* </p>
|
||||
* <p>
|
||||
* When this service is started, it creates a Runnable and starts it in a new Thread. The
|
||||
* Runnable does a synchronized lock on the service's Binder object for 15 seconds, then issues
|
||||
* a stopSelf(). The net effect is a new worker thread that takes 15 seconds to run and then
|
||||
* shuts down the entire service. The activity restarts the service after 15 more seconds, when the
|
||||
* countdown timer triggers again.
|
||||
* </p>
|
||||
* <p>
|
||||
* This service is provided as the service under test for the sample test application
|
||||
* AlarmServiceTest.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note: Since this sample is based on the Android 1.5 platform, it does not implement
|
||||
* onStartCommand. See the Javadoc for android.app.Service for more details.
|
||||
* </p>
|
||||
*/
|
||||
public class AlarmService extends Service {
|
||||
// Defines a label for the thread that this service starts
|
||||
private static final String ALARM_SERVICE_THREAD = "AlarmService";
|
||||
|
||||
// Defines 15 seconds
|
||||
public static final long WAIT_TIME_SECONDS = 15;
|
||||
|
||||
// Define the number of milliseconds in one second
|
||||
public static final long MILLISECS_PER_SEC = 1000;
|
||||
|
||||
/*
|
||||
* For testing purposes, the following variables are defined as fields and set to
|
||||
* package visibility.
|
||||
*/
|
||||
|
||||
// The NotificationManager used to send notifications to the status bar.
|
||||
NotificationManager mNotificationManager;
|
||||
|
||||
// An Intent that displays the client if the user clicks the notification.
|
||||
PendingIntent mContentIntent;
|
||||
|
||||
// A Notification to send to the Notification Manager when the service is started.
|
||||
Notification mNotification;
|
||||
|
||||
// A Binder, used as the lock object for the worker thread.
|
||||
IBinder mBinder = new AlarmBinder();
|
||||
|
||||
// A Thread object that will run the background task
|
||||
Thread mWorkThread;
|
||||
|
||||
// The Runnable that is the service's "task". This illustrates how a service is used to
|
||||
// offload work from a client.
|
||||
Runnable mWorkTask = new Runnable() {
|
||||
public void run() {
|
||||
// Sets the wait time to 15 seconds, simulating a 15-second background task.
|
||||
long waitTime = System.currentTimeMillis() + WAIT_TIME_SECONDS * MILLISECS_PER_SEC;
|
||||
|
||||
// Puts the wait in a while loop to ensure that it actually waited 15 seconds.
|
||||
// This covers the situation where an interrupt might have overridden the wait.
|
||||
while (System.currentTimeMillis() < waitTime) {
|
||||
// Waits for 15 seconds or interruption
|
||||
synchronized (mBinder) {
|
||||
try {
|
||||
// Waits for 15 seconds or until an interrupt triggers an exception.
|
||||
// If an interrupt occurs, the wait is recalculated to ensure a net
|
||||
// wait of 15 seconds.
|
||||
mBinder.wait(waitTime - System.currentTimeMillis());
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Stops the current service. In response, Android calls onDestroy().
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a full concrete subclass of Binder, rather than doing it in line, for readability.
|
||||
*/
|
||||
public class AlarmBinder extends Binder {
|
||||
// Constructor. Calls the super constructor to set up the instance.
|
||||
public AlarmBinder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
|
||||
throws RemoteException {
|
||||
|
||||
// Call the parent method with the arguments passed in
|
||||
return super.onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the service when it is first started by a call to startService() or
|
||||
* bindService().
|
||||
*/
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// Gets a handle to the system mNotification service.
|
||||
mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
||||
|
||||
// Updates the status bar to indicate that this service is running.
|
||||
showNotification();
|
||||
|
||||
// Creates a new thread. A new thread is used so that the service's work doesn't block
|
||||
// anything on the calling client's thread. By default, a service runs in the same
|
||||
// process and thread as the client that starts it.
|
||||
mWorkThread = new Thread(
|
||||
null, // threadgroup (in this case, null)
|
||||
mWorkTask, // the Runnable that will run in this thread
|
||||
ALARM_SERVICE_THREAD
|
||||
);
|
||||
// Starts the thread
|
||||
mWorkThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the service in response to the stopSelf() issued when the wait is over. Other
|
||||
* clients that use this service could stop it by issuing a stopService() or a stopSelf() on
|
||||
* the service object.
|
||||
*/
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// Cancels the status bar mNotification based on its ID, which is set in showNotification().
|
||||
mNotificationManager.cancel(R.string.alarm_service_started);
|
||||
|
||||
// Sends a notification to the screen.
|
||||
Toast.makeText(
|
||||
this, // the current context
|
||||
R.string.alarm_service_finished, // the message to show
|
||||
Toast.LENGTH_LONG // how long to keep the message on the screen
|
||||
).show(); // show the text
|
||||
}
|
||||
|
||||
// Returns the service's binder object to clients that issue onBind().
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a notification in the status bar that this service is running. This method
|
||||
* also creates an Intent for the AlarmActivity client and attaches it to the notification
|
||||
* line. If the user clicks the line in the expanded status window, the Intent triggers
|
||||
* AlarmActivity.
|
||||
*/
|
||||
private void showNotification() {
|
||||
// Sets the text to use for the status bar and status list views.
|
||||
CharSequence notificationText = getText(R.string.alarm_service_started);
|
||||
|
||||
// Sets the icon, status bar text, and display time for the mNotification.
|
||||
mNotification = new Notification(
|
||||
R.drawable.stat_sample, // the status icon
|
||||
notificationText, // the status text
|
||||
System.currentTimeMillis() // the time stamp
|
||||
);
|
||||
|
||||
// Sets up the Intent that starts AlarmActivity
|
||||
mContentIntent = PendingIntent.getActivity(
|
||||
this, // Start the Activity in the current context
|
||||
0, // not used
|
||||
new Intent(this, AlarmActivity.class), // A new Intent for AlarmActivity
|
||||
0 // Use an existing activity instance if available
|
||||
);
|
||||
|
||||
// Creates a new content view for the mNotification. The view appears when the user
|
||||
// shows the expanded status window.
|
||||
mNotification.setLatestEventInfo(
|
||||
this, // Put the content view in the current context
|
||||
getText(R.string.alarm_service_label), // The text to use as the label of the entry
|
||||
notificationText, // The text to use as the contents of the entry
|
||||
mContentIntent // The intent to send when the entry is clicked
|
||||
);
|
||||
|
||||
// Sets a unique ID for the notification and sends it to NotificationManager to be
|
||||
// displayed. The ID is the integer marker for the notification string, which is
|
||||
// guaranteed to be unique within the entire application.
|
||||
mNotificationManager.notify(
|
||||
R.string.alarm_service_started, // unique id for the mNotification
|
||||
mNotification // the mNotification object
|
||||
);
|
||||
}
|
||||
}
|
||||
54
samples/Alarm/tests/AndroidManifest.xml
Normal file
54
samples/Alarm/tests/AndroidManifest.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Declare the contents of this Android test package. The xmlns:android
|
||||
attribute brings in the Android platform namespace, and the
|
||||
"package" attribute provides a unique name for the package.
|
||||
If you use this file as a template in your own test package, you must change
|
||||
the package name from "com.example.android" to one that you own or have
|
||||
control over.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.newalarm.test"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<!--
|
||||
Must use the application element to include the uses-library element.
|
||||
-->
|
||||
<application>
|
||||
<!--
|
||||
Tells Android to include this library in the test package's class loader.
|
||||
The test runner is not included by default in a manifest file.
|
||||
-->
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
<!--
|
||||
Specifies that the test package requires API platform level 3 (Android 1.5) or above.
|
||||
The installer will not install this package onto a device or emulator that is running an
|
||||
older platform version.
|
||||
-->
|
||||
<uses-sdk android:minSdkVersion="3" />
|
||||
<!--
|
||||
Declares the instrumentation for this application. The instrumentation class is
|
||||
specified by the "name" attribute, and must name a subclass of
|
||||
android.app.Instrumentation. The application that is run by the instrumentation object is
|
||||
specified by the "targetPackage" attribute.
|
||||
-->
|
||||
<instrumentation
|
||||
android:targetPackage="com.example.android.newalarm"
|
||||
android:name="android.test.InstrumentationTestRunner" />
|
||||
</manifest>
|
||||
50
samples/Alarm/tests/_index.html
Normal file
50
samples/Alarm/tests/_index.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<p>
|
||||
This sample is the test application for the <a href="../Alarm/index.html">Alarm</a>
|
||||
sample application. It tests the application's <code>AlarmService</code> service.
|
||||
</p>
|
||||
<p>
|
||||
The test application uses the
|
||||
<a href="../../../reference/android/test/ServiceTestCase.html">
|
||||
<code>ServiceTestCase</code></a> test case class,
|
||||
which extends the JUnit <a href="../../../reference/junit/framework/TestCase.html">
|
||||
<code>TestCase</code></a> class. The test runner is
|
||||
<a href="../../../reference/android/test/InstrumentationTestRunner.html">
|
||||
<code>InstrumentationTestRunner</code></a>.
|
||||
</p>
|
||||
<p>
|
||||
The application shows how to set up a test application project,
|
||||
how to create the <a href="AndroidManifest.html"><code>AndroidManifest.xml</code></a>
|
||||
file for a test application, and how to set up a test case class for a service. The
|
||||
test case class, <a href="src/com/android/example/newalarm/ServiceAlarmTest.html">
|
||||
<code>AlarmServiceTest</code></a>, contains tests that demonstrate the following
|
||||
Android test patterns:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Test setup: The <code>setUp()</code> method re-initializes the state of the
|
||||
service under test before each test is run.
|
||||
</li>
|
||||
<li>
|
||||
Service start: The <code>Service.testServiceCreate()</code> test confirms that the
|
||||
service starts correctly and initializes the variables it needs to provide its
|
||||
services.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
The <a href="AndroidManifest.html">manifest</a> declares an <code><instrumentation></code>
|
||||
element that links the test application with the application under test. Specifically, the
|
||||
element's <code>android:name</code> attribute specifies <code>InstrumentationTestRunner</code>
|
||||
as the instrumentation to use. The <code>android:targetPackage</code> attribute specifies
|
||||
<code>com.android.example.newalarm</code> as the name of the Android package that contains the
|
||||
service under test.
|
||||
</p>
|
||||
<p class="note">
|
||||
<strong>Note:</strong> <code>AlarmServiceTest.java</code> uses the Java package name
|
||||
<code>com.example.android.newalarm</code>, which is the same package used by service under
|
||||
test, <code>AlarmService.java</code>. This allows the test class to access members in the
|
||||
service under test that are defined with package visibility. To prevent conflicts, though,
|
||||
the generated java file <code>R.java</code> for <code>AlarmServiceTest</code> uses the
|
||||
Java package name <code>com.example.android.newalarm.test</code>. For the same reason, the
|
||||
Android package name for the test application (specified in the manifest file), is
|
||||
<code>com.example.android.newalarm.test</code>.
|
||||
</p>
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.newalarm;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.test.ServiceTestCase;
|
||||
import com.example.android.newalarm.AlarmService;
|
||||
|
||||
/**
|
||||
* Test class for the Alarm sample test package. This test class tests the AlarmService
|
||||
* service component.
|
||||
*/
|
||||
public class AlarmServiceTest extends ServiceTestCase<AlarmService> {
|
||||
// Contains an Intent used to start the service
|
||||
Intent mStartServiceIntent;
|
||||
|
||||
// Contains a handle to the system alarm service
|
||||
AlarmService mService;
|
||||
|
||||
/**
|
||||
* Constructor for the test class. Test classes that are run by InstrumentationTestRunner
|
||||
* must provide a constructor with no arguments that calls the base class constructor as its
|
||||
* first statement.
|
||||
*/
|
||||
public AlarmServiceTest() {
|
||||
super(AlarmService.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets up the test fixture. This method is called before each test
|
||||
*/
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
|
||||
super.setUp();
|
||||
|
||||
// Sets up an intent to start the service under test
|
||||
mStartServiceIntent = new Intent(this.getSystemContext(),AlarmService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the test fixture
|
||||
* Called after each test method. If you override the method, call super.tearDown() as the
|
||||
* last statement in your override.
|
||||
*/
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
// Always call the super constructor when overriding tearDown()
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the service's onCreate() method. Starts the service using startService(Intent)
|
||||
*/
|
||||
public void testServiceCreate() {
|
||||
// Starts the service under test
|
||||
this.startService(mStartServiceIntent);
|
||||
|
||||
// Gets a handle to the service under test.
|
||||
mService = this.getService();
|
||||
|
||||
// Asserts that the Notification Manager was created in the service under test.
|
||||
assertNotNull(mService.mNotificationManager);
|
||||
|
||||
// Asserts that the PendingIntent for the expanded status window was created
|
||||
assertNotNull(mService.mContentIntent);
|
||||
|
||||
// Asserts that the notification was created
|
||||
assertNotNull(mService.mNotification);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,9 @@
|
||||
<uses-permission android:name="android.permission.SEND_SMS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
|
||||
<!-- For android.media.audiofx.Visualizer -->
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
|
||||
<!-- We will request access to the camera, saying we require a camera
|
||||
of some sort but not one with autofocus capability. -->
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
@@ -1884,6 +1887,13 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".media.AudioFxDemo" android:label="Media/AudioFx">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.SAMPLE_CODE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- ************************************* -->
|
||||
<!-- APPWIDGET PACKAGE SAMPLES -->
|
||||
<!-- ************************************* -->
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.apis.media;
|
||||
|
||||
import com.example.android.apis.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.audiofx.Equalizer;
|
||||
import android.media.audiofx.Visualizer;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class AudioFxDemo extends Activity {
|
||||
private static final String TAG = "AudioFxDemo";
|
||||
|
||||
private static final float VISUALIZER_HEIGHT_DIP = 50f;
|
||||
|
||||
private MediaPlayer mMediaPlayer;
|
||||
private Visualizer mVisualizer;
|
||||
private Equalizer mEqualizer;
|
||||
|
||||
private LinearLayout mLinearLayout;
|
||||
private VisualizerView mVisualizerView;
|
||||
private TextView mStatusTextView;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
|
||||
mStatusTextView = new TextView(this);
|
||||
|
||||
mLinearLayout = new LinearLayout(this);
|
||||
mLinearLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
mLinearLayout.addView(mStatusTextView);
|
||||
|
||||
setContentView(mLinearLayout);
|
||||
|
||||
// Create the MediaPlayer
|
||||
mMediaPlayer = MediaPlayer.create(this, R.raw.test_cbr);
|
||||
Log.d(TAG, "MediaPlayer audio session ID: " + mMediaPlayer.getAudioSessionId());
|
||||
|
||||
setupVisualizerFxAndUI();
|
||||
setupEqualizerFxAndUI();
|
||||
|
||||
// Make sure the visualizer is enabled only when you actually want to receive data, and
|
||||
// when it makes sense to receive data.
|
||||
mVisualizer.setEnabled(true);
|
||||
|
||||
// When the stream ends, we don't need to collect any more data. We don't do this in
|
||||
// setupVisualizerFxAndUI because we likely want to have more, non-Visualizer related code
|
||||
// in this callback.
|
||||
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||
public void onCompletion(MediaPlayer mediaPlayer) {
|
||||
mVisualizer.setEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
mMediaPlayer.start();
|
||||
mStatusTextView.setText("Playing audio...");
|
||||
}
|
||||
|
||||
private void setupEqualizerFxAndUI() {
|
||||
// Create the Equalizer object (an AudioEffect subclass) and attach it to our media player,
|
||||
// with a default priority (0).
|
||||
mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
|
||||
mEqualizer.setEnabled(true);
|
||||
|
||||
TextView eqTextView = new TextView(this);
|
||||
eqTextView.setText("Equalizer:");
|
||||
mLinearLayout.addView(eqTextView);
|
||||
|
||||
short bands = mEqualizer.getNumberOfBands();
|
||||
|
||||
final short minEQLevel = mEqualizer.getBandLevelRange()[0];
|
||||
final short maxEQLevel = mEqualizer.getBandLevelRange()[1];
|
||||
|
||||
for (short i = 0; i < bands; i++) {
|
||||
final short band = i;
|
||||
|
||||
TextView freqTextView = new TextView(this);
|
||||
freqTextView.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
freqTextView.setText((mEqualizer.getCenterFreq(band) / 1000) + " Hz");
|
||||
mLinearLayout.addView(freqTextView);
|
||||
|
||||
LinearLayout row = new LinearLayout(this);
|
||||
row.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
TextView minDbTextView = new TextView(this);
|
||||
minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
minDbTextView.setText((minEQLevel / 100) + " dB");
|
||||
|
||||
TextView maxDbTextView = new TextView(this);
|
||||
maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
maxDbTextView.setText((maxEQLevel / 100) + " dB");
|
||||
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.weight = 1;
|
||||
SeekBar bar = new SeekBar(this);
|
||||
bar.setLayoutParams(layoutParams);
|
||||
bar.setMax(maxEQLevel - minEQLevel);
|
||||
bar.setProgress(mEqualizer.getBandLevel(band));
|
||||
|
||||
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
public void onProgressChanged(SeekBar seekBar, int progress,
|
||||
boolean fromUser) {
|
||||
mEqualizer.setBandLevel(band, (short) (progress + minEQLevel));
|
||||
}
|
||||
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
|
||||
row.addView(minDbTextView);
|
||||
row.addView(bar);
|
||||
row.addView(maxDbTextView);
|
||||
|
||||
mLinearLayout.addView(row);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupVisualizerFxAndUI() {
|
||||
// Create a VisualizerView (defined below), which will render the simplified audio
|
||||
// wave form to a Canvas.
|
||||
mVisualizerView = new VisualizerView(this);
|
||||
mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.FILL_PARENT,
|
||||
(int)(VISUALIZER_HEIGHT_DIP * getResources().getDisplayMetrics().density)));
|
||||
mLinearLayout.addView(mVisualizerView);
|
||||
|
||||
// Create the Visualizer object and attach it to our media player.
|
||||
mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
|
||||
mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
|
||||
mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
|
||||
public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes,
|
||||
int samplingRate) {
|
||||
mVisualizerView.updateVisualizer(bytes);
|
||||
}
|
||||
|
||||
public void onFftDataCapture(Visualizer visualizer, byte[] bytes, int samplingRate) {}
|
||||
}, Visualizer.getMaxCaptureRate() / 2, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (isFinishing() && mMediaPlayer != null) {
|
||||
mVisualizer.release();
|
||||
mEqualizer.release();
|
||||
mMediaPlayer.release();
|
||||
mMediaPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple class that draws waveform data received from a
|
||||
* {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture }
|
||||
*/
|
||||
class VisualizerView extends View {
|
||||
private byte[] mBytes;
|
||||
private float[] mPoints;
|
||||
private Rect mRect = new Rect();
|
||||
|
||||
private Paint mForePaint = new Paint();
|
||||
|
||||
public VisualizerView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mBytes = null;
|
||||
|
||||
mForePaint.setStrokeWidth(1f);
|
||||
mForePaint.setAntiAlias(true);
|
||||
mForePaint.setColor(Color.rgb(0, 128, 255));
|
||||
}
|
||||
|
||||
public void updateVisualizer(byte[] bytes) {
|
||||
mBytes = bytes;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (mBytes == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mPoints == null || mPoints.length < mBytes.length * 4) {
|
||||
mPoints = new float[mBytes.length * 4];
|
||||
}
|
||||
|
||||
mRect.set(0, 0, getWidth(), getHeight());
|
||||
|
||||
for (int i = 0; i < mBytes.length - 1; i++) {
|
||||
mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
|
||||
mPoints[i * 4 + 1] = mRect.height() / 2
|
||||
+ ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
|
||||
mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);
|
||||
mPoints[i * 4 + 3] = mRect.height() / 2
|
||||
+ ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2) / 128;
|
||||
}
|
||||
|
||||
canvas.drawLines(mPoints, mForePaint);
|
||||
}
|
||||
}
|
||||
16
samples/SipDemo/Android.mk
Normal file
16
samples/SipDemo/Android.mk
Normal file
@@ -0,0 +1,16 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := samples
|
||||
|
||||
# Only compile source java files in this apk.
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
|
||||
LOCAL_PACKAGE_NAME := SipDemo
|
||||
|
||||
LOCAL_SDK_VERSION := current
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
# Use the following include to make our test apk.
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||
44
samples/SipDemo/AndroidManifest.xml
Normal file
44
samples/SipDemo/AndroidManifest.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.sip">
|
||||
<application android:icon="@drawable/icon" android:label="SipDemo">
|
||||
<activity android:name=".WalkieTalkieActivity"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".SipSettings" android:label="set_preferences"/>
|
||||
|
||||
|
||||
<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver"/>
|
||||
</application>
|
||||
<uses-sdk android:minSdkVersion="9" />
|
||||
<uses-permission android:name="android.permission.USE_SIP" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
|
||||
<uses-feature android:name="android.hardware.sip.voip" android:required="true" />
|
||||
<uses-feature android:name="android.hardware.wifi" android:required="true" />
|
||||
<uses-feature android:name="android.hardware.microphone" android:required="true" />
|
||||
</manifest>
|
||||
52
samples/SipDemo/_index.html
Normal file
52
samples/SipDemo/_index.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<p>This is a demo application highlighting how to make internet-based calls with
|
||||
the SIP API. The application uses a walkie-talkie style interface, allowing you
|
||||
to only be heard when the button is pushed down.</p>
|
||||
|
||||
<p>The source code for this demo app shows how to accomplish three key things
|
||||
with SIP: Make a call, receive a call, and signal to the Android platform that
|
||||
your app wants to receive incoming SIP calls, so that they can be handled from
|
||||
within the application.</p>
|
||||
|
||||
|
||||
<p>The application includes:<p>
|
||||
<ul> <li><a
|
||||
href="src/com/example/android/sip/SipSettings.html"><code>SipSettings</code></a>
|
||||
— a <code>PreferenceActivity</code> that supplies basic settings for SIP
|
||||
authentication.</li> <li><a
|
||||
href="src/com/example/android/sip/cube1/IncomingCallReceiver.html"><code>
|
||||
IncomingCallReceiver</code></a> — a <code>BroadcastReceiver</code>
|
||||
that listens for incoming SIP calls and passes them to
|
||||
<code>WalkieTalkieActivity</code> for handling.</li> <li><a
|
||||
href="src/com/example/android/sip/WalkieTalkieActivity.html"><code>WalkieTalkieActivity</code></a>
|
||||
— a activity that login to SIP provider and registers the device to
|
||||
receive incoming SIP, handles incoming calls and makes outgoing calls, managing
|
||||
UI during the call.</li> </ul>
|
||||
<p>If you are developing an application that uses the SIP API, remember that the
|
||||
feature is supported only on Android 2.3 (API level 9) and higher versions of
|
||||
the platform. Also, among devices running Android 2.3 (API level 9) or higher,
|
||||
not all devices will offer SIP support. To ensure that your application can only
|
||||
be installed on devices that are capable of supporting SIP, remember to add the
|
||||
following to the application's manifest before publishing to Android Market:</p>
|
||||
<ul> <li><code><uses-sdk android:minSdkVersion="9" /></code>, which
|
||||
indicates to Android Market and the platform that your application requires
|
||||
Android 2.3 or higher. For more information, see <a
|
||||
href="../../../guide/appendix/api-levels.html">API Levels</a> and the
|
||||
documentation for the <a
|
||||
href="../../../guide/topics/manifest/uses-sdk-element.html"><code><uses-sdk></code></a>
|
||||
element.</li> </ul> <p>To control how Android Market filters your application
|
||||
from devices that do not support SIP, remember to add the following to the
|
||||
application's manifest <ul> <li><code><uses-feature
|
||||
android:name="android.hardware.sip.voip" /></code>, which tells Android
|
||||
Market that your application uses the SIP API. The declaration should include
|
||||
an <code>android:required</code> attribute that indicates whether you want
|
||||
Android Market to filter the application from devices that do not offer SIP
|
||||
support. Other <code><uses-feature></code> declarations may also be
|
||||
needed, depending on your implementation. For more information, see the
|
||||
documentation for the <a
|
||||
href="../../../guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a>
|
||||
element.</li> </ul>
|
||||
<p>For more information about using the SIP API, see the <a
|
||||
href="../../../reference/android/net/sip/package-summary.html"><code>android.net.sip</a></code>
|
||||
documentation. </p>
|
||||
|
||||
<img alt="" src="../images/SipDemo.png" />
|
||||
23
samples/SipDemo/res/drawable/btn_record.xml
Normal file
23
samples/SipDemo/res/drawable/btn_record.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/btn_speak_pressed" />
|
||||
<item android:state_selected="true" android:drawable="@drawable/btn_speak_pressed" />
|
||||
<item android:drawable="@drawable/btn_speak_normal" />
|
||||
</selector>
|
||||
|
||||
BIN
samples/SipDemo/res/drawable/btn_speak_normal.png
Normal file
BIN
samples/SipDemo/res/drawable/btn_speak_normal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
samples/SipDemo/res/drawable/btn_speak_pressed.png
Normal file
BIN
samples/SipDemo/res/drawable/btn_speak_pressed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
BIN
samples/SipDemo/res/drawable/btn_speak_selected.png
Normal file
BIN
samples/SipDemo/res/drawable/btn_speak_selected.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
samples/SipDemo/res/drawable/icon.png
Normal file
BIN
samples/SipDemo/res/drawable/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
45
samples/SipDemo/res/layout/call_address_dialog.xml
Normal file
45
samples/SipDemo/res/layout/call_address_dialog.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/calladdress_view"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:text="@+string/contactAddress"
|
||||
android:gravity="left"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/calladdress_edit"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:scrollHorizontally="true"
|
||||
android:autoText="false"
|
||||
android:capitalize="none"
|
||||
android:gravity="fill_horizontal"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
</LinearLayout>
|
||||
49
samples/SipDemo/res/layout/walkietalkie.xml
Normal file
49
samples/SipDemo/res/layout/walkietalkie.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<RelativeLayout android:padding="12dp"
|
||||
android:id="@+id/mainlayout"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sipLabel"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
/>
|
||||
|
||||
<ToggleButton
|
||||
android:layout_height="400dp"
|
||||
android:layout_width="400dp"
|
||||
android:text="@+string/talk"
|
||||
android:id="@+id/pushToTalk"
|
||||
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="@drawable/btn_record"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:layout_marginTop="-20dp" />
|
||||
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
||||
22
samples/SipDemo/res/values/strings.xml
Normal file
22
samples/SipDemo/res/values/strings.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">SIP Demo</string>
|
||||
<string name="contactAddress">SIP Address to contact</string>
|
||||
<string name="talk">Talk</string>
|
||||
</resources>
|
||||
38
samples/SipDemo/res/xml/preferences.xml
Normal file
38
samples/SipDemo/res/xml/preferences.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<EditTextPreference
|
||||
android:name="SIP Username"
|
||||
android:summary="Username for your SIP Account"
|
||||
android:defaultValue=""
|
||||
android:title="Enter Username"
|
||||
android:key="namePref" />
|
||||
<EditTextPreference
|
||||
android:name="SIP Domain"
|
||||
android:summary="Domain for your SIP Account"
|
||||
android:defaultValue=""
|
||||
android:title="Enter Domain"
|
||||
android:key="domainPref" />
|
||||
<EditTextPreference
|
||||
android:name="SIP Password"
|
||||
android:summary="Password for your SIP Account"
|
||||
android:defaultValue=""
|
||||
android:title="Enter Password"
|
||||
android:key="passPref"
|
||||
android:password="true" />
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.sip;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.sip.*;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity.
|
||||
*/
|
||||
public class IncomingCallReceiver extends BroadcastReceiver {
|
||||
/**
|
||||
* Processes the incoming call, answers it, and hands it over to the
|
||||
* WalkieTalkieActivity.
|
||||
* @param context The context under which the receiver is running.
|
||||
* @param intent The intent being received.
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
SipAudioCall incomingCall = null;
|
||||
try {
|
||||
|
||||
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
|
||||
@Override
|
||||
public void onRinging(SipAudioCall call, SipProfile caller) {
|
||||
try {
|
||||
call.answerCall(30);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context;
|
||||
|
||||
incomingCall = wtActivity.manager.takeAudioCall(intent, listener);
|
||||
incomingCall.answerCall(30);
|
||||
incomingCall.startAudio();
|
||||
incomingCall.setSpeakerMode(true);
|
||||
if(incomingCall.isMuted()) {
|
||||
incomingCall.toggleMute();
|
||||
}
|
||||
|
||||
wtActivity.call = incomingCall;
|
||||
|
||||
wtActivity.updateStatus(incomingCall);
|
||||
|
||||
} catch (Exception e) {
|
||||
if (incomingCall != null) {
|
||||
incomingCall.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
34
samples/SipDemo/src/com/example/android/sip/SipSettings.java
Normal file
34
samples/SipDemo/src/com/example/android/sip/SipSettings.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.sip;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
|
||||
/**
|
||||
* Handles SIP authentication settings for the Walkie Talkie app.
|
||||
*/
|
||||
public class SipSettings extends PreferenceActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
// Note that none of the preferences are actually defined here.
|
||||
// They're all in the XML file res/xml/preferences.xml.
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.sip;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.*;
|
||||
import android.net.sip.*;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
/**
|
||||
* Handles all calling, receiving calls, and UI interaction in the WalkieTalkie app.
|
||||
*/
|
||||
public class WalkieTalkieActivity extends Activity implements View.OnTouchListener {
|
||||
|
||||
public String sipAddress = null;
|
||||
|
||||
public SipManager manager = null;
|
||||
public SipProfile me = null;
|
||||
public SipAudioCall call = null;
|
||||
public IncomingCallReceiver callReceiver;
|
||||
|
||||
private static final int CALL_ADDRESS = 1;
|
||||
private static final int SET_AUTH_INFO = 2;
|
||||
private static final int UPDATE_SETTINGS_DIALOG = 3;
|
||||
private static final int HANG_UP = 4;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.walkietalkie);
|
||||
|
||||
ToggleButton pushToTalkButton = (ToggleButton) findViewById(R.id.pushToTalk);
|
||||
pushToTalkButton.setOnTouchListener(this);
|
||||
|
||||
// Set up the intent filter. This will be used to fire an
|
||||
// IncomingCallReceiver when someone calls the SIP address used by this
|
||||
// application.
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("android.SipDemo.INCOMING_CALL");
|
||||
callReceiver = new IncomingCallReceiver();
|
||||
this.registerReceiver(callReceiver, filter);
|
||||
|
||||
// "Push to talk" can be a serious pain when the screen keeps turning off.
|
||||
// Let's prevent that.
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
initializeManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
// When we get back from the preference setting Activity, assume
|
||||
// settings have changed, and re-login with new auth info.
|
||||
initializeManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (call != null) {
|
||||
call.close();
|
||||
}
|
||||
|
||||
closeLocalProfile();
|
||||
|
||||
if (callReceiver != null) {
|
||||
this.unregisterReceiver(callReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
public void initializeManager() {
|
||||
if(manager == null) {
|
||||
manager = SipManager.newInstance(this);
|
||||
}
|
||||
|
||||
initializeLocalProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs you into your SIP provider, registering this device as the location to
|
||||
* send SIP calls to for your SIP address.
|
||||
*/
|
||||
public void initializeLocalProfile() {
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (me != null) {
|
||||
closeLocalProfile();
|
||||
}
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
|
||||
String username = prefs.getString("namePref", "");
|
||||
String domain = prefs.getString("domainPref", "");
|
||||
String password = prefs.getString("passPref", "");
|
||||
|
||||
if (username.length() == 0 || domain.length() == 0 || password.length() == 0) {
|
||||
showDialog(UPDATE_SETTINGS_DIALOG);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
SipProfile.Builder builder = new SipProfile.Builder(username, domain);
|
||||
builder.setPassword(password);
|
||||
me = builder.build();
|
||||
|
||||
Intent i = new Intent();
|
||||
i.setAction("android.SipDemo.INCOMING_CALL");
|
||||
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
|
||||
manager.open(me, pi, null);
|
||||
|
||||
|
||||
// This listener must be added AFTER manager.open is called,
|
||||
// Otherwise the methods aren't guaranteed to fire.
|
||||
|
||||
manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
|
||||
public void onRegistering(String localProfileUri) {
|
||||
updateStatus("Registering with SIP Server...");
|
||||
}
|
||||
|
||||
public void onRegistrationDone(String localProfileUri, long expiryTime) {
|
||||
updateStatus("Ready");
|
||||
}
|
||||
|
||||
public void onRegistrationFailed(String localProfileUri, int errorCode,
|
||||
String errorMessage) {
|
||||
updateStatus("Registration failed. Please check settings.");
|
||||
}
|
||||
});
|
||||
} catch (ParseException pe) {
|
||||
updateStatus("Connection Error.");
|
||||
} catch (SipException se) {
|
||||
updateStatus("Connection error.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes out your local profile, freeing associated objects into memory
|
||||
* and unregistering your device from the server.
|
||||
*/
|
||||
public void closeLocalProfile() {
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (me != null) {
|
||||
manager.close(me.getUriString());
|
||||
}
|
||||
} catch (Exception ee) {
|
||||
Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an outgoing call.
|
||||
*/
|
||||
public void initiateCall() {
|
||||
|
||||
updateStatus(sipAddress);
|
||||
|
||||
try {
|
||||
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
|
||||
// Much of the client's interaction with the SIP Stack will
|
||||
// happen via listeners. Even making an outgoing call, don't
|
||||
// forget to set up a listener to set things up once the call is established.
|
||||
@Override
|
||||
public void onCallEstablished(SipAudioCall call) {
|
||||
call.startAudio();
|
||||
call.setSpeakerMode(true);
|
||||
call.toggleMute();
|
||||
updateStatus(call);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallEnded(SipAudioCall call) {
|
||||
updateStatus("Ready.");
|
||||
}
|
||||
};
|
||||
|
||||
call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
|
||||
if (me != null) {
|
||||
try {
|
||||
manager.close(me.getUriString());
|
||||
} catch (Exception ee) {
|
||||
Log.i("WalkieTalkieActivity/InitiateCall",
|
||||
"Error when trying to close manager.", ee);
|
||||
ee.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (call != null) {
|
||||
call.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status box at the top of the UI with a messege of your choice.
|
||||
* @param status The String to display in the status box.
|
||||
*/
|
||||
public void updateStatus(final String status) {
|
||||
// Be a good citizen. Make sure UI changes fire on the UI thread.
|
||||
this.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
TextView labelView = (TextView) findViewById(R.id.sipLabel);
|
||||
labelView.setText(status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status box with the SIP address of the current call.
|
||||
* @param call The current, active call.
|
||||
*/
|
||||
public void updateStatus(SipAudioCall call) {
|
||||
String useName = call.getPeerProfile().getDisplayName();
|
||||
if(useName == null) {
|
||||
useName = call.getPeerProfile().getUserName();
|
||||
}
|
||||
updateStatus(useName + "@" + call.getPeerProfile().getSipDomain());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates whether or not the user's voice is muted, depending on whether the button is pressed.
|
||||
* @param v The View where the touch event is being fired.
|
||||
* @param event The motion to act on.
|
||||
* @return boolean Returns false to indicate that the parent view should handle the touch event
|
||||
* as it normally would.
|
||||
*/
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (call == null) {
|
||||
return false;
|
||||
} else if (event.getAction() == MotionEvent.ACTION_DOWN && call != null && call.isMuted()) {
|
||||
call.toggleMute();
|
||||
} else if (event.getAction() == MotionEvent.ACTION_UP && !call.isMuted()) {
|
||||
call.toggleMute();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, CALL_ADDRESS, 0, "Call someone");
|
||||
menu.add(0, SET_AUTH_INFO, 0, "Edit your SIP Info.");
|
||||
menu.add(0, HANG_UP, 0, "End Current Call.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case CALL_ADDRESS:
|
||||
showDialog(CALL_ADDRESS);
|
||||
break;
|
||||
case SET_AUTH_INFO:
|
||||
updatePreferences();
|
||||
break;
|
||||
case HANG_UP:
|
||||
if(call != null) {
|
||||
try {
|
||||
call.endCall();
|
||||
} catch (SipException se) {
|
||||
Log.d("WalkieTalkieActivity/onOptionsItemSelected",
|
||||
"Error ending call.", se);
|
||||
}
|
||||
call.close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
switch (id) {
|
||||
case CALL_ADDRESS:
|
||||
|
||||
LayoutInflater factory = LayoutInflater.from(this);
|
||||
final View textBoxView = factory.inflate(R.layout.call_address_dialog, null);
|
||||
return new AlertDialog.Builder(this)
|
||||
.setTitle("Call Someone.")
|
||||
.setView(textBoxView)
|
||||
.setPositiveButton(
|
||||
android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
EditText textField = (EditText)
|
||||
(textBoxView.findViewById(R.id.calladdress_edit));
|
||||
sipAddress = textField.getText().toString();
|
||||
initiateCall();
|
||||
|
||||
}
|
||||
})
|
||||
.setNegativeButton(
|
||||
android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
// Noop.
|
||||
}
|
||||
})
|
||||
.create();
|
||||
|
||||
case UPDATE_SETTINGS_DIALOG:
|
||||
return new AlertDialog.Builder(this)
|
||||
.setMessage("Please update your SIP Account Settings.")
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
updatePreferences();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(
|
||||
android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
// Noop.
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updatePreferences() {
|
||||
Intent settingsActivity = new Intent(getBaseContext(),
|
||||
SipSettings.class);
|
||||
startActivity(settingsActivity);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user