diff options
| author | Stuart MacDonald <stuart.macdonald@stericsson.com> | 2011-03-14 15:14:54 +0100 |
|---|---|---|
| committer | Alin Jerpelea <jerpelea@gmail.com> | 2013-01-15 07:09:54 +0200 |
| commit | 40bab89ba75723ffc6b59808899007388c2b20a0 (patch) | |
| tree | 3f50745d7bfa40a5cb4e2590671a6dcc5f6e6943 | |
| parent | d8de3d8354e0e1f4e6801db681cea366f553362d (diff) | |
| download | android_development-ics.tar.gz android_development-ics.tar.bz2 android_development-ics.zip | |
FM Radio: Add support for FM Radio in Androidics
Two sample applications for the proposed FM Radio API.
Change-Id: I8a0b0099f6ea20d9f53822127498d5e603eb3255
Signed-off-by: Christian Bejram <christian.bejram@stericsson.com>
Conflicts:
build/sdk.atree
50 files changed, 1167 insertions, 0 deletions
diff --git a/build/sdk.atree b/build/sdk.atree index 038dafc08..b6c42eb65 100644 --- a/build/sdk.atree +++ b/build/sdk.atree @@ -205,6 +205,8 @@ development/samples/RenderScript/FountainFbo samples/${PLATFORM_NAME}/RenderSc development/samples/RenderScript/HelloCompute samples/${PLATFORM_NAME}/RenderScript/HelloCompute development/samples/RenderScript/HelloWorld samples/${PLATFORM_NAME}/RenderScript/HelloWorld development/samples/RenderScript/MiscSamples samples/${PLATFORM_NAME}/RenderScript/MiscSamples +development/samples/FmRadioReceiver samples/${PLATFORM_NAME}/FmRadioReceiver +development/samples/FmRadioTransmitter samples/${PLATFORM_NAME}/FmRadioTransmitter # NOTICE files are copied by build/core/Makefile from sdk.git sdk/files/sdk_files_NOTICE.txt samples/${PLATFORM_NAME}/NOTICE.txt diff --git a/samples/FmRadioReceiver/Android.mk b/samples/FmRadioReceiver/Android.mk new file mode 100755 index 000000000..177ce9330 --- /dev/null +++ b/samples/FmRadioReceiver/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := samples + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := FmRadioReceiver + +include $(BUILD_PACKAGE) diff --git a/samples/FmRadioReceiver/AndroidManifest.xml b/samples/FmRadioReceiver/AndroidManifest.xml new file mode 100755 index 000000000..f1aae6548 --- /dev/null +++ b/samples/FmRadioReceiver/AndroidManifest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.fmradioreceiver" android:versionCode="1" + android:versionName="1.0"> + <application android:icon="@drawable/icon" android:label="@string/app_name"> + <activity android:name=".FmRadioReceiver" android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + <uses-permission android:name="com.stericsson.permission.FM_RADIO_TRANSMITTER"></uses-permission> + <uses-permission android:name="com.stericsson.permission.FM_RADIO_RECEIVER"></uses-permission> +</manifest> diff --git a/samples/FmRadioReceiver/_index.html b/samples/FmRadioReceiver/_index.html new file mode 100755 index 000000000..080591e9c --- /dev/null +++ b/samples/FmRadioReceiver/_index.html @@ -0,0 +1,15 @@ +<p>FmRadioReceiver is a sample application that demonstrates the use of the +<a href="../../../reference/android/fm/FmReceiver.html">android.fm.FmReceiver</a> +class to implement a FM Radio receiver in an application. The application allows the +user to tune to any local radio stations, switch between them, scan for new stations and +mute the radio. It also allows the user to change the radio band to their suit their location. +The use of listeners is shown to display the tuned station name if RDS data is present.</p> + +<p>The FmRadioReceiver.java file in FmRadioReceiver also illustrates the interaction with +the MediaPlayer. </p> + +<p><strong>See also:</strong><br/> +<a href="../../../reference/android/fm/FmBand.html">FmBand</a></p> +<a href="../../../reference/android/fm/FmTransmitter.html">FmTransmitter</a></p> + +<img alt="" src="../images/FmRadioReceiver.png" /> diff --git a/samples/FmRadioReceiver/res/drawable/backward.png b/samples/FmRadioReceiver/res/drawable/backward.png Binary files differnew file mode 100755 index 000000000..c53408f3a --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/backward.png diff --git a/samples/FmRadioReceiver/res/drawable/backwardbutton.xml b/samples/FmRadioReceiver/res/drawable/backwardbutton.xml new file mode 100755 index 000000000..22ff20159 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/backwardbutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/backwardpress" /> + <item android:state_focused="true" android:drawable="@drawable/backwardpress" /> + <item android:drawable="@drawable/backward" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioReceiver/res/drawable/backwardpress.png b/samples/FmRadioReceiver/res/drawable/backwardpress.png Binary files differnew file mode 100755 index 000000000..3fcfada18 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/backwardpress.png diff --git a/samples/FmRadioReceiver/res/drawable/forward.png b/samples/FmRadioReceiver/res/drawable/forward.png Binary files differnew file mode 100755 index 000000000..a3f6a75f8 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/forward.png diff --git a/samples/FmRadioReceiver/res/drawable/forwardbutton.xml b/samples/FmRadioReceiver/res/drawable/forwardbutton.xml new file mode 100755 index 000000000..bbefffc87 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/forwardbutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/forwardpress" /> + <item android:state_focused="true" android:drawable="@drawable/forwardpress" /> + <item android:drawable="@drawable/forward" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioReceiver/res/drawable/forwardpress.png b/samples/FmRadioReceiver/res/drawable/forwardpress.png Binary files differnew file mode 100755 index 000000000..417b99db6 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/forwardpress.png diff --git a/samples/FmRadioReceiver/res/drawable/icon.png b/samples/FmRadioReceiver/res/drawable/icon.png Binary files differnew file mode 100755 index 000000000..a07c69fa5 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/icon.png diff --git a/samples/FmRadioReceiver/res/drawable/pause.png b/samples/FmRadioReceiver/res/drawable/pause.png Binary files differnew file mode 100755 index 000000000..ff5ffd71f --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/pause.png diff --git a/samples/FmRadioReceiver/res/drawable/pausebutton.xml b/samples/FmRadioReceiver/res/drawable/pausebutton.xml new file mode 100755 index 000000000..92b7c894e --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/pausebutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/pausepress" /> + <item android:state_focused="true" android:drawable="@drawable/pausepress" /> + <item android:drawable="@drawable/pause" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioReceiver/res/drawable/pausepress.png b/samples/FmRadioReceiver/res/drawable/pausepress.png Binary files differnew file mode 100755 index 000000000..e4d978ca0 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/pausepress.png diff --git a/samples/FmRadioReceiver/res/drawable/play.png b/samples/FmRadioReceiver/res/drawable/play.png Binary files differnew file mode 100755 index 000000000..5b77d3b75 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/play.png diff --git a/samples/FmRadioReceiver/res/drawable/playbutton.xml b/samples/FmRadioReceiver/res/drawable/playbutton.xml new file mode 100755 index 000000000..12ba91e13 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/playbutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/playpress" /> + <item android:state_focused="true" android:drawable="@drawable/playpress" /> + <item android:drawable="@drawable/play" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioReceiver/res/drawable/playpress.png b/samples/FmRadioReceiver/res/drawable/playpress.png Binary files differnew file mode 100755 index 000000000..c0063c7c2 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/playpress.png diff --git a/samples/FmRadioReceiver/res/drawable/rescan.png b/samples/FmRadioReceiver/res/drawable/rescan.png Binary files differnew file mode 100755 index 000000000..2d2cc2aa1 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/rescan.png diff --git a/samples/FmRadioReceiver/res/drawable/rescanbutton.xml b/samples/FmRadioReceiver/res/drawable/rescanbutton.xml new file mode 100755 index 000000000..9585ff587 --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/rescanbutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/rescanpress" /> + <item android:state_focused="true" android:drawable="@drawable/rescanpress" /> + <item android:drawable="@drawable/rescan" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioReceiver/res/drawable/rescanpress.png b/samples/FmRadioReceiver/res/drawable/rescanpress.png Binary files differnew file mode 100755 index 000000000..a03ce7aaf --- /dev/null +++ b/samples/FmRadioReceiver/res/drawable/rescanpress.png diff --git a/samples/FmRadioReceiver/res/layout/main.xml b/samples/FmRadioReceiver/res/layout/main.xml new file mode 100755 index 000000000..355823d1d --- /dev/null +++ b/samples/FmRadioReceiver/res/layout/main.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout android:layout_width="fill_parent" + android:layout_height="fill_parent" android:orientation="vertical" + xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/MainWindow" + android:gravity="center"> + <TextView android:layout_width="fill_parent" + android:layout_height="wrap_content" android:text="@string/fmradio" + android:textSize="50px" android:id="@+id/PSNTextView" android:gravity="center"></TextView> + <TextView android:layout_width="fill_parent" + android:layout_height="wrap_content" android:id="@+id/FrequencyTextView" + android:lines="1" android:textSize="90px" android:gravity="center" + android:text="@string/dashes"></TextView> + <LinearLayout android:id="@+id/TopRow" + android:layout_height="wrap_content" android:layout_width="fill_parent" + android:gravity="center"> + <LinearLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" android:layout_weight="1" + android:gravity="right" android:paddingRight="10px"> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" android:id="@+id/ScanDown" + android:background="@drawable/backwardbutton"/> + </LinearLayout> + <LinearLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" android:layout_weight="1" + android:gravity="left" android:paddingLeft="10px"> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" android:id="@+id/ScanUp" + android:background="@drawable/forwardbutton" /> + </LinearLayout> + </LinearLayout> + <LinearLayout android:id="@+id/BottonRow" + android:layout_height="wrap_content" android:layout_width="fill_parent" + android:gravity="center"> + <LinearLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" android:layout_weight="1" + android:gravity="right" android:paddingRight="10px"> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" android:id="@+id/FullScan" + android:background="@drawable/rescanbutton"/> + </LinearLayout> + <LinearLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" android:layout_weight="1" + android:gravity="left" android:paddingLeft="10px"> + <Button android:layout_height="wrap_content" + android:layout_width="wrap_content" android:id="@+id/Pause" + android:background="@drawable/pausebutton" /> + </LinearLayout> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/samples/FmRadioReceiver/res/values/strings.xml b/samples/FmRadioReceiver/res/values/strings.xml new file mode 100755 index 000000000..ec714c20e --- /dev/null +++ b/samples/FmRadioReceiver/res/values/strings.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">FmRadioReceiver</string> + <string name="band_select">Select Band</string> + <string name="band_us">U.S</string> + <string name="band_eu">Europe</string> + <string name="band_ja">Japan</string> + <string name="band_ch">China</string> + <string name="station_select">Select Station</string> + <string name="fmradio">FM RADIO</string> + <string name="dashes">- - - -</string> +</resources> diff --git a/samples/FmRadioReceiver/src/com/example/android/fmradioreceiver/FmRadioReceiver.java b/samples/FmRadioReceiver/src/com/example/android/fmradioreceiver/FmRadioReceiver.java new file mode 100755 index 000000000..269dd84f6 --- /dev/null +++ b/samples/FmRadioReceiver/src/com/example/android/fmradioreceiver/FmRadioReceiver.java @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2011 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.fmradioreceiver; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.media.MediaPlayer; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; +import com.stericsson.hardware.fm.FmBand; +import com.stericsson.hardware.fm.FmReceiver; + +import java.io.IOException; + + +public class FmRadioReceiver extends Activity { + + // The string to find in android logs + private static final String LOG_TAG = "FM Radio Demo App"; + + // The string to show that the station list is empty + private static final String EMPTY_STATION_LIST = "No stations available"; + + // The 50kHz channel offset + private static final int CHANNEL_OFFSET_50KHZ = 50; + + // The base menu identifier + private static final int BASE_OPTION_MENU = 0; + + // The band menu identifier + private static final int BAND_SELECTION_MENU = 1; + + // The station menu identifier + private static final int STATION_SELECTION_MENU = 2; + + // Handle to the Media Player that plays the audio from the selected station + private MediaPlayer mMediaPlayer; + + // The scan listener that receives the return values from the scans + private FmReceiver.OnScanListener mReceiverScanListener; + + // The listener that receives the RDS data from the current channel + private FmReceiver.OnRDSDataFoundListener mReceiverRdsDataFoundListener; + + // The started listener is activated when the radio has started + private FmReceiver.OnStartedListener mReceiverStartedListener; + + // Displays the currently tuned frequency + private TextView mFrequencyTextView; + + // Displays the current station name if there is adequate RDS data + private TextView mStationNameTextView; + + // Handle to the FM radio Band object + private FmBand mFmBand; + + // Handle to the FM radio receiver object + private FmReceiver mFmReceiver; + + // Indicates if we are in the initialization sequence + private boolean mInit = true; + + // Indicates that we are restarting the app + private boolean mRestart = false; + + // Protects the MediaPlayer and FmReceiver against rapid muting causing + // errors + private boolean mPauseMutex = false; + + // Array of the available stations in MHz + private ArrayAdapter<CharSequence> mMenuAdapter; + + // The name of the storage string + public static final String PREFS_NAME = "FMRadioPrefsFile"; + + // The menu items + public static final int FM_BAND = Menu.FIRST; + + public static final int BAND_US = Menu.FIRST + 1; + + public static final int BAND_EU = Menu.FIRST + 2; + + public static final int BAND_JAPAN = Menu.FIRST + 3; + + public static final int BAND_CHINA = Menu.FIRST + 4; + + public static final int STATION_SELECT = Menu.FIRST + 5; + + public static final int STATION_SELECT_MENU_ITEMS = STATION_SELECT + 1; + + // The currently selected FM Radio band + private int mSelectedBand; + + /** + * Required method from parent class + * + * @param icicle - The previous instance of this app + */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.main); + mFmReceiver = (FmReceiver) getSystemService("fm_receiver"); + SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); + mSelectedBand = settings.getInt("selectedBand", 1); + mFmBand = new FmBand(mSelectedBand); + setupButtons(); + } + + /** + * Starts up the listeners and the FM radio if it isn't already active + */ + @Override + protected void onStart() { + super.onStart(); + mReceiverScanListener = new com.stericsson.hardware.fm.FmReceiver.OnScanListener() { + + // FullScan results + public void onFullScan(int[] frequency, int[] signalStrength, boolean aborted) { + ((Button) findViewById(R.id.FullScan)).setEnabled(true); + showToast("Fullscan complete", Toast.LENGTH_LONG); + mMenuAdapter.clear(); + if (frequency.length == 0) { + mMenuAdapter.add(EMPTY_STATION_LIST); + return; + } + for (int i = 0; i < frequency.length; i++) { + String a = Double.toString((double) frequency[i] / 1000); + if (mFmBand.getChannelOffset() == CHANNEL_OFFSET_50KHZ) { + a = String.format(a, "%.2f"); + } else { + a = String.format(a, "%.1f"); + } + mMenuAdapter.add(a); + } + if (mInit) { + mInit = false; + try { + mFmReceiver.setFrequency(frequency[0]); + mFrequencyTextView.setText(mMenuAdapter.getItem(0).toString()); + } catch (IOException e) { + showToast("Unable to set the receiver's frequency", Toast.LENGTH_LONG); + } catch (IllegalArgumentException e) { + showToast("Unable to set the receiver's frequency", Toast.LENGTH_LONG); + } + } + } + + // Returns the new frequency. + public void onScan(int tunedFrequency, int signalStrength, int scanDirection, boolean aborted) { + String a = Double.toString((double) tunedFrequency / 1000); + if (mFmBand.getChannelOffset() == CHANNEL_OFFSET_50KHZ) { + mFrequencyTextView.setText(String.format(a, "%.2f")); + } else { + mFrequencyTextView.setText(String.format(a, "%.1f")); + } + ((Button) findViewById(R.id.ScanUp)).setEnabled(true); + ((Button) findViewById(R.id.ScanDown)).setEnabled(true); + } + }; + mReceiverRdsDataFoundListener = new com.stericsson.hardware.fm.FmReceiver.OnRDSDataFoundListener() { + + // Receives the current frequency's RDS Data + public void onRDSDataFound(Bundle rdsData, int frequency) { + if (rdsData.containsKey("PSN")) { + mStationNameTextView.setText(rdsData.getString("PSN")); + } + } + }; + + mReceiverStartedListener = new com.stericsson.hardware.fm.FmReceiver.OnStartedListener() { + + public void onStarted() { + // Activate all the buttons + ((Button) findViewById(R.id.ScanUp)).setEnabled(true); + ((Button) findViewById(R.id.ScanDown)).setEnabled(true); + ((Button) findViewById(R.id.Pause)).setEnabled(true); + ((Button) findViewById(R.id.FullScan)).setEnabled(true); + initialBandscan(); + startAudio(); + } + }; + + mFmReceiver.addOnScanListener(mReceiverScanListener); + mFmReceiver.addOnRDSDataFoundListener(mReceiverRdsDataFoundListener); + mFmReceiver.addOnStartedListener(mReceiverStartedListener); + + if (!mRestart) { + turnRadioOn(); + } + mRestart = false; + } + + /** + * Stops the FM Radio listeners + */ + @Override + protected void onRestart() { + super.onRestart(); + mRestart = true; + } + + /** + * Stops the FM Radio listeners + */ + @Override + protected void onStop() { + super.onStop(); + + if (mFmReceiver != null) { + mFmReceiver.removeOnScanListener(mReceiverScanListener); + mFmReceiver.removeOnRDSDataFoundListener(mReceiverRdsDataFoundListener); + mFmReceiver.removeOnStartedListener(mReceiverStartedListener); + } + } + + /** + * Saves the FmBand for next time the program is used and closes the radio + * and media player. + */ + @Override + protected void onDestroy() { + super.onDestroy(); + SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); + SharedPreferences.Editor editor = settings.edit(); + editor.putInt("selectedBand", mSelectedBand); + editor.commit(); + try { + mFmReceiver.reset(); + } catch (IOException e) { + Log.e(LOG_TAG, "Unable to reset correctly", e); + } + if (mMediaPlayer != null) { + mMediaPlayer.release(); + mMediaPlayer = null; + } + } + + /** + * Starts the initial bandscan in it's own thread + */ + private void initialBandscan() { + Thread bandscanThread = new Thread() { + public void run() { + try { + mFmReceiver.startFullScan(); + } catch (IllegalStateException e) { + showToast("Unable to start the scan", Toast.LENGTH_LONG); + return; + } + } + }; + bandscanThread.start(); + } + + /** + * Helper method to display toast + */ + private void showToast(final String text, final int duration) { + runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(getApplicationContext(), text, duration).show(); + } + }); + } + + /** + * Starts the FM receiver and makes the buttons appear inactive + */ + private void turnRadioOn() { + + try { + mFmReceiver.startAsync(mFmBand); + // Darken the the buttons + ((Button) findViewById(R.id.ScanUp)).setEnabled(false); + ((Button) findViewById(R.id.ScanDown)).setEnabled(false); + ((Button) findViewById(R.id.Pause)).setEnabled(false); + ((Button) findViewById(R.id.FullScan)).setEnabled(false); + showToast("Scanning initial stations", Toast.LENGTH_LONG); + } catch (IOException e) { + showToast("Unable to start the radio receiver.", Toast.LENGTH_LONG); + } catch (IllegalStateException e) { + showToast("Unable to start the radio receiver.", Toast.LENGTH_LONG); + } + } + + /** + * Starts the FM receiver and makes the buttons appear inactive + */ + private void startAudio() { + + mMediaPlayer = new MediaPlayer(); + try { + mMediaPlayer.setDataSource("fmradio://rx"); + mMediaPlayer.prepare(); + mMediaPlayer.start(); + } catch (IOException e) { + showToast("Unable to start the media player", Toast.LENGTH_LONG); + } + } + + /** + * Sets up the buttons and their listeners + */ + private void setupButtons() { + + mMenuAdapter = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item); + mMenuAdapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice); + mMenuAdapter.add("No stations available"); + mFrequencyTextView = (TextView) findViewById(R.id.FrequencyTextView); + mStationNameTextView = (TextView) findViewById(R.id.PSNTextView); + + final Button scanUp = (Button) findViewById(R.id.ScanUp); + scanUp.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + try { + mFmReceiver.scanUp(); + } catch (IllegalStateException e) { + showToast("Unable to ScanUp", Toast.LENGTH_LONG); + return; + } + scanUp.setEnabled(false); + } + }); + final Button scanDown = (Button) findViewById(R.id.ScanDown); + scanDown.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + try { + mFmReceiver.scanDown(); + } catch (IllegalStateException e) { + showToast("Unable to ScanDown", Toast.LENGTH_LONG); + return; + } + scanDown.setEnabled(false); + } + }); + final Button pause = (Button) findViewById(R.id.Pause); + pause.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + if (mFmReceiver.getState() == FmReceiver.STATE_PAUSED && mPauseMutex != true) { + try { + mPauseMutex = true; + mFmReceiver.resume(); + mMediaPlayer.start(); + pause.setBackgroundResource(R.drawable.pausebutton); + } catch (IOException e) { + showToast("Unable to resume", Toast.LENGTH_LONG); + } catch (IllegalStateException e) { + showToast("Unable to resume", Toast.LENGTH_LONG); + } + mPauseMutex = false; + } else if (mFmReceiver.getState() == FmReceiver.STATE_STARTED + && mPauseMutex != true) { + try { + mPauseMutex = true; + mMediaPlayer.pause(); + mFmReceiver.pause(); + pause.setBackgroundResource(R.drawable.playbutton); + } catch (IOException e) { + showToast("Unable to pause", Toast.LENGTH_LONG); + } catch (IllegalStateException e) { + showToast("Unable to pause", Toast.LENGTH_LONG); + } + mPauseMutex = false; + } else if (mPauseMutex) { + showToast("MediaPlayer busy. Please wait and try again.", Toast.LENGTH_LONG); + } else { + Log.i(LOG_TAG, "No action: incorrect state - " + mFmReceiver.getState()); + } + } + }); + final Button fullScan = (Button) findViewById(R.id.FullScan); + fullScan.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + try { + fullScan.setEnabled(false); + showToast("Scanning for stations", Toast.LENGTH_LONG); + mFmReceiver.startFullScan(); + } catch (IllegalStateException e) { + showToast("Unable to start the scan", Toast.LENGTH_LONG); + } + } + }); + } + + /** + * Sets up the options menu when the menu button is pushed, dynamic + * population of the station select menu + */ + public boolean onPrepareOptionsMenu(Menu menu) { + menu.clear(); + boolean result = super.onCreateOptionsMenu(menu); + SubMenu subMenu = menu.addSubMenu(BASE_OPTION_MENU, FM_BAND, Menu.NONE, + R.string.band_select); + subMenu.setIcon(android.R.drawable.ic_menu_mapmode); + // Populate the band selection menu + subMenu.add(BAND_SELECTION_MENU, BAND_US, Menu.NONE, R.string.band_us); + subMenu.add(BAND_SELECTION_MENU, BAND_EU, Menu.NONE, R.string.band_eu); + subMenu.add(BAND_SELECTION_MENU, BAND_JAPAN, Menu.NONE, R.string.band_ja); + subMenu.add(BAND_SELECTION_MENU, BAND_CHINA, Menu.NONE, R.string.band_ch); + subMenu.setGroupCheckable(BAND_SELECTION_MENU, true, true); + subMenu.getItem(mSelectedBand).setChecked(true); + + subMenu = menu.addSubMenu(BASE_OPTION_MENU, STATION_SELECT, Menu.NONE, + R.string.station_select); + subMenu.setIcon(android.R.drawable.ic_menu_agenda); + + // Dynamically populate the station select menu each time the option + // button is pushed + if (mMenuAdapter.isEmpty()) { + subMenu.setGroupEnabled(STATION_SELECTION_MENU, false); + } else { + subMenu.setGroupEnabled(STATION_SELECTION_MENU, true); + for (int i = 0; i < mMenuAdapter.getCount(); i++) { + subMenu.add(STATION_SELECTION_MENU, STATION_SELECT_MENU_ITEMS + i, Menu.NONE, + mMenuAdapter.getItem(i)); + } + subMenu.setGroupCheckable(STATION_SELECTION_MENU, true, true); + } + return result; + } + + public int getSelectStationMenuItem(MenuItem item) { + return item.getItemId() - STATION_SELECT_MENU_ITEMS; + } + + /** + * React to a selection in the option menu + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + switch (item.getGroupId()) { + case BAND_SELECTION_MENU: + switch (item.getItemId()) { + case BAND_US: + mSelectedBand = FmBand.BAND_US; + item.setChecked(true); + break; + case BAND_EU: + mSelectedBand = FmBand.BAND_EU; + item.setChecked(true); + break; + case BAND_JAPAN: + mSelectedBand = FmBand.BAND_JAPAN; + item.setChecked(true); + break; + case BAND_CHINA: + mSelectedBand = FmBand.BAND_CHINA; + item.setChecked(true); + break; + default: + break; + } + mFmBand = new FmBand(mSelectedBand); + try { + mFmReceiver.reset(); + } catch (IOException e) { + showToast("Unable to restart the FM Radio", Toast.LENGTH_LONG); + } + if (mMediaPlayer != null) { + mMediaPlayer.release(); + mMediaPlayer = null; + } + turnRadioOn(); + break; + case STATION_SELECTION_MENU: + try { + if (!mMenuAdapter.getItem(getSelectStationMenuItem(item)).toString().matches( + EMPTY_STATION_LIST)) { + mFmReceiver.setFrequency((int) (Double.valueOf(mMenuAdapter.getItem( + getSelectStationMenuItem(item)).toString()) * 1000)); + mFrequencyTextView.setText(mMenuAdapter.getItem( + getSelectStationMenuItem(item)).toString()); + } + } catch (IOException e) { + showToast("Unable to set the frequency", Toast.LENGTH_LONG); + } catch (IllegalStateException e) { + showToast("Unable to set the frequency", Toast.LENGTH_LONG); + } catch (IllegalArgumentException e) { + showToast("Unable to set the frequency", Toast.LENGTH_LONG); + } + + break; + default: + break; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/samples/FmRadioTransmitter/Android.mk b/samples/FmRadioTransmitter/Android.mk new file mode 100755 index 000000000..0c25b3525 --- /dev/null +++ b/samples/FmRadioTransmitter/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := samples + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := FmRadioTransmitter + +LOCAL_SDK_VERSION := current + +include $(BUILD_PACKAGE) diff --git a/samples/FmRadioTransmitter/AndroidManifest.xml b/samples/FmRadioTransmitter/AndroidManifest.xml new file mode 100755 index 000000000..ec0d33648 --- /dev/null +++ b/samples/FmRadioTransmitter/AndroidManifest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.fmradiotransmitter" android:versionCode="1" + android:versionName="1.0"> + <application android:icon="@drawable/icon" android:label="@string/app_name"> + <activity android:name=".FmRadioTransmitter" android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> + <uses-permission android:name="android.permission.FM_RADIO_TRANSMITTER"></uses-permission> + <uses-permission android:name="android.permission.FM_RADIO_RECEIVER"></uses-permission> +</manifest>
\ No newline at end of file diff --git a/samples/FmRadioTransmitter/_index.html b/samples/FmRadioTransmitter/_index.html new file mode 100755 index 000000000..0a286e206 --- /dev/null +++ b/samples/FmRadioTransmitter/_index.html @@ -0,0 +1,14 @@ +<p>FmRadioTransmitter is a sample application that demonstrates the use of the +<a href="../../../reference/android/fm/FmTransmitter.html">android.fm.FmTransmitter</a> +class to implement a FM Radio transmitter in an application. The application allows the +user to scan the 88MHz-90MHz frequency region for the channel with the least signal +interference. The application then transmits any audio using the FM Radio chip.</p> + +<p>The suggested use is to start a long media file in the MediaPlayer application +then turn on the FmRadioTransmitter sample application.</p> + +<p><strong>See also:</strong><br/> +<a href="../../../reference/android/fm/FmBand.html">FmBand</a></p> +<a href="../../../reference/android/fm/FmReceiver.html">FmReceiver</a></p> + +<img alt="" src="../images/FmRadioTransmitter.png" /> diff --git a/samples/FmRadioTransmitter/res/drawable/anim.xml b/samples/FmRadioTransmitter/res/drawable/anim.xml new file mode 100755 index 000000000..4a06a4fb6 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/anim.xml @@ -0,0 +1,7 @@ +<animation-list xmlns:android="http://schemas.android.com/apk/res/android" + android:oneshot="false"> + <item android:drawable="@drawable/transmit1" android:duration="200" /> + <item android:drawable="@drawable/transmit2" android:duration="200" /> + <item android:drawable="@drawable/transmit3" android:duration="200" /> + <item android:drawable="@drawable/transmit4" android:duration="200" /> +</animation-list>
\ No newline at end of file diff --git a/samples/FmRadioTransmitter/res/drawable/backward.png b/samples/FmRadioTransmitter/res/drawable/backward.png Binary files differnew file mode 100755 index 000000000..c53408f3a --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/backward.png diff --git a/samples/FmRadioTransmitter/res/drawable/backwardbutton.xml b/samples/FmRadioTransmitter/res/drawable/backwardbutton.xml new file mode 100755 index 000000000..22ff20159 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/backwardbutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/backwardpress" /> + <item android:state_focused="true" android:drawable="@drawable/backwardpress" /> + <item android:drawable="@drawable/backward" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioTransmitter/res/drawable/backwardpress.png b/samples/FmRadioTransmitter/res/drawable/backwardpress.png Binary files differnew file mode 100755 index 000000000..3fcfada18 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/backwardpress.png diff --git a/samples/FmRadioTransmitter/res/drawable/forward.png b/samples/FmRadioTransmitter/res/drawable/forward.png Binary files differnew file mode 100755 index 000000000..a3f6a75f8 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/forward.png diff --git a/samples/FmRadioTransmitter/res/drawable/forwardbutton.xml b/samples/FmRadioTransmitter/res/drawable/forwardbutton.xml new file mode 100755 index 000000000..bbefffc87 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/forwardbutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/forwardpress" /> + <item android:state_focused="true" android:drawable="@drawable/forwardpress" /> + <item android:drawable="@drawable/forward" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioTransmitter/res/drawable/forwardpress.png b/samples/FmRadioTransmitter/res/drawable/forwardpress.png Binary files differnew file mode 100755 index 000000000..417b99db6 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/forwardpress.png diff --git a/samples/FmRadioTransmitter/res/drawable/icon.png b/samples/FmRadioTransmitter/res/drawable/icon.png Binary files differnew file mode 100755 index 000000000..a07c69fa5 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/icon.png diff --git a/samples/FmRadioTransmitter/res/drawable/rescan.png b/samples/FmRadioTransmitter/res/drawable/rescan.png Binary files differnew file mode 100755 index 000000000..2d2cc2aa1 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/rescan.png diff --git a/samples/FmRadioTransmitter/res/drawable/rescanbutton.xml b/samples/FmRadioTransmitter/res/drawable/rescanbutton.xml new file mode 100755 index 000000000..9585ff587 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/rescanbutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/rescanpress" /> + <item android:state_focused="true" android:drawable="@drawable/rescanpress" /> + <item android:drawable="@drawable/rescan" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioTransmitter/res/drawable/rescanpress.png b/samples/FmRadioTransmitter/res/drawable/rescanpress.png Binary files differnew file mode 100755 index 000000000..a03ce7aaf --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/rescanpress.png diff --git a/samples/FmRadioTransmitter/res/drawable/transmit1.png b/samples/FmRadioTransmitter/res/drawable/transmit1.png Binary files differnew file mode 100755 index 000000000..ecf4803ad --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmit1.png diff --git a/samples/FmRadioTransmitter/res/drawable/transmit2.png b/samples/FmRadioTransmitter/res/drawable/transmit2.png Binary files differnew file mode 100755 index 000000000..19aaeda09 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmit2.png diff --git a/samples/FmRadioTransmitter/res/drawable/transmit3.png b/samples/FmRadioTransmitter/res/drawable/transmit3.png Binary files differnew file mode 100755 index 000000000..5303824ad --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmit3.png diff --git a/samples/FmRadioTransmitter/res/drawable/transmit4.png b/samples/FmRadioTransmitter/res/drawable/transmit4.png Binary files differnew file mode 100755 index 000000000..39e41900d --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmit4.png diff --git a/samples/FmRadioTransmitter/res/drawable/transmitgo.png b/samples/FmRadioTransmitter/res/drawable/transmitgo.png Binary files differnew file mode 100755 index 000000000..af8639cc7 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmitgo.png diff --git a/samples/FmRadioTransmitter/res/drawable/transmitgobutton.xml b/samples/FmRadioTransmitter/res/drawable/transmitgobutton.xml new file mode 100755 index 000000000..b486bbecb --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmitgobutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/transmitgopress" /> + <item android:state_focused="true" android:drawable="@drawable/transmitgopress" /> + <item android:drawable="@drawable/transmitgo" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioTransmitter/res/drawable/transmitgopress.png b/samples/FmRadioTransmitter/res/drawable/transmitgopress.png Binary files differnew file mode 100755 index 000000000..b9319c973 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmitgopress.png diff --git a/samples/FmRadioTransmitter/res/drawable/transmitstop.png b/samples/FmRadioTransmitter/res/drawable/transmitstop.png Binary files differnew file mode 100755 index 000000000..a1871ba65 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmitstop.png diff --git a/samples/FmRadioTransmitter/res/drawable/transmitstopbutton.xml b/samples/FmRadioTransmitter/res/drawable/transmitstopbutton.xml new file mode 100755 index 000000000..79c2db9d1 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmitstopbutton.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/transmitstoppress" /> + <item android:state_focused="true" android:drawable="@drawable/transmitstoppress" /> + <item android:drawable="@drawable/transmitstop" /> +</selector>
\ No newline at end of file diff --git a/samples/FmRadioTransmitter/res/drawable/transmitstoppress.png b/samples/FmRadioTransmitter/res/drawable/transmitstoppress.png Binary files differnew file mode 100755 index 000000000..eee730647 --- /dev/null +++ b/samples/FmRadioTransmitter/res/drawable/transmitstoppress.png diff --git a/samples/FmRadioTransmitter/res/layout/main.xml b/samples/FmRadioTransmitter/res/layout/main.xml new file mode 100755 index 000000000..1669bb36a --- /dev/null +++ b/samples/FmRadioTransmitter/res/layout/main.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout android:layout_width="fill_parent" + android:layout_height="fill_parent" android:orientation="vertical" + android:gravity="center" xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/MainWindow"> + <ImageView android:layout_y="40px" android:layout_height="80px" + android:layout_x="120px" android:id="@+id/TransmitIcon" + android:layout_width="160px"></ImageView> + <TextView android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="center_horizontal" + android:text="@string/dashes" android:padding="40px" android:id="@+id/FrequencyTextView" + android:lines="1" android:textSize="60px"></TextView> + <LinearLayout android:layout_width="fill_parent" + android:orientation="horizontal" android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" android:id="@+id/ButtonRow" + android:paddingBottom="40px"> + <LinearLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" android:layout_weight="1" + android:gravity="center" android:id="@+id/Left"> + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" android:padding="10px" + android:id="@+id/BlockScan" android:background="@drawable/rescanbutton" /> + </LinearLayout> + <LinearLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" android:layout_weight="1" + android:gravity="center" android:id="@+id/Centre"> + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" android:padding="10px" + android:id="@+id/ScanDown" android:background="@drawable/backwardbutton" /> + </LinearLayout> + <LinearLayout android:layout_width="fill_parent" + android:layout_height="wrap_content" android:layout_weight="1" + android:gravity="center" android:id="@+id/Right"> + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" android:padding="10px" + android:id="@+id/ScanUp" android:background="@drawable/forwardbutton" /> + + </LinearLayout> + </LinearLayout> + <Button android:id="@+id/Transmit" android:layout_x="40px" + android:layout_y="300px" android:layout_height="60px" + android:layout_width="200px" android:background="@drawable/transmitgobutton" /> +</LinearLayout>
\ No newline at end of file diff --git a/samples/FmRadioTransmitter/res/values/strings.xml b/samples/FmRadioTransmitter/res/values/strings.xml new file mode 100755 index 000000000..32d8048fe --- /dev/null +++ b/samples/FmRadioTransmitter/res/values/strings.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">FM Radio Transmitter</string> + <string name="band_select">Select Band</string> + <string name="band_us">U.S</string> + <string name="band_eu">Europe</string> + <string name="band_ja">Japan</string> + <string name="band_ch">China</string> + <string name="dashes">----</string> +</resources> diff --git a/samples/FmRadioTransmitter/src/com/example/android/fmradiotransmitter/FmRadioTransmitter.java b/samples/FmRadioTransmitter/src/com/example/android/fmradiotransmitter/FmRadioTransmitter.java new file mode 100755 index 000000000..e06095e93 --- /dev/null +++ b/samples/FmRadioTransmitter/src/com/example/android/fmradiotransmitter/FmRadioTransmitter.java @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2011 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, + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.fmradiotransmitter; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.hardware.fm.FmBand; +import android.hardware.fm.FmTransmitter; +import android.graphics.drawable.AnimationDrawable; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +public class FmRadioTransmitter extends Activity { + + // Scan range that works for all bands + private static final int MINSCANRANGE = 88000; + + private static final int MAXSCANRANGE = 90000; + + // The 50kHz channel offset + private static final int CHANNEL_OFFSET_50KHZ = 50; + + // The scan listener that receives the return values from the scans + private FmTransmitter.OnScanListener mTransmitterScanListener; + + // The started listener is activated when the radio has started + private FmTransmitter.OnStartedListener mTransmitterStartedListener; + + // Displays the currently tuned frequency + private TextView mFrequencyTextView; + + // Handle to the FM radio Band object + private FmBand mFmBand; + + // Handle to the FM radio transmitter object + private FmTransmitter mFmTransmitter; + + // The frequency that the radio is currently tuned to. + private int mCurrentfrequency; + + // The current band's channel offset. + private int mFrequencyIncrement; + + // Handle to the Transmitter's Animation. + private AnimationDrawable mTransmitAnimation; + + // The name of the storage string + public static final String PREFS_NAME = "FMRadioPrefsFile"; + + // The currently selected FM Radio band + private int mSelectedBand; + + // The base menu identifier + private static final int BASE_OPTION_MENU = 0; + + // The band menu identifier + private static final int BAND_SELECTION_MENU = 1; + + // The menu items + public static final int FM_BAND = Menu.FIRST; + + public static final int BAND_US = Menu.FIRST + 1; + + public static final int BAND_EU = Menu.FIRST + 2; + + public static final int BAND_JAPAN = Menu.FIRST + 3; + + public static final int BAND_CHINA = Menu.FIRST + 4; + + /** + * Required method from parent class + * + * @param icicle - The previous instance of this app + */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.main); + mFmTransmitter = (FmTransmitter) getSystemService(Context.RADIO_FM_TRANSMITTER_SERVICE); + SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); + mSelectedBand = settings.getInt("selectedBand", 1); + mFmBand = new FmBand(mSelectedBand); + mFrequencyIncrement = mFmBand.getChannelOffset(); + setupButtons(); + setupAnimation(); + } + + /** + * Starts up the listeners and the FM radio if it isn't already active + */ + @Override + protected void onStart() { + super.onStart(); + mTransmitterStartedListener = new android.hardware.fm.FmTransmitter.OnStartedListener() { + + public void onStarted() { + mTransmitAnimation.start(); + ((Button) findViewById(R.id.Transmit)) + .setBackgroundResource(R.drawable.transmitstopbutton); + mCurrentfrequency = mFmBand.getDefaultFrequency(); + mFrequencyIncrement = mFmBand.getChannelOffset(); + blockscan(); + } + }; + + mTransmitterScanListener = new android.hardware.fm.FmTransmitter.OnScanListener() { + + public void onBlockScan(int[] frequency, int[] signalStrength, boolean aborted) { + ((Button) findViewById(R.id.BlockScan)).setEnabled(true); + int minFreq = 0; + int minSigStr = Integer.MAX_VALUE; + for (int i = 0; i < frequency.length; i++) { + if (signalStrength[i] < minSigStr) { + minSigStr = signalStrength[i]; + minFreq = frequency[i]; + } + } + try { + mFmTransmitter.setFrequency(minFreq); + } catch (Exception e) { + showToast("Unable to set the frequency after scanning", Toast.LENGTH_LONG); + return; + } + mCurrentfrequency = minFreq; + displayFreq(); + } + }; + mFmTransmitter.addOnScanListener(mTransmitterScanListener); + mFmTransmitter.addOnStartedListener(mTransmitterStartedListener); + } + + /** + * Stops the FM Radio listeners + */ + @Override + protected void onStop() { + super.onStop(); + if (mFmTransmitter != null) { + mFmTransmitter.removeOnScanListener(mTransmitterScanListener); + mFmTransmitter.removeOnStartedListener(mTransmitterStartedListener); + } + } + + /** + * Saves the FmBand for next time the program is used and closes the radio + * and media player. + */ + @Override + protected void onDestroy() { + super.onDestroy(); + SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); + SharedPreferences.Editor editor = settings.edit(); + editor.putInt("selectedBand", mSelectedBand); + editor.commit(); + try { + mFmTransmitter.reset(); + } catch (Exception e) { + showToast("Unable to reset the radio hardware.", Toast.LENGTH_LONG); + } + } + + /** + * Starts a blockscan in a seperate thread. + */ + protected void blockscan() { + showToast("Performining blockscan", Toast.LENGTH_LONG); + Thread blockscanThread = new Thread() { + public void run() { + try { + mFmTransmitter.startBlockScan(MINSCANRANGE, MAXSCANRANGE); + } catch (Exception e) { + showToast("Unable to start BlockScan between " + String.valueOf(MINSCANRANGE) + + "-" + String.valueOf(MAXSCANRANGE), Toast.LENGTH_LONG); + return; + } + } + }; + blockscanThread.start(); + } + + /** + * Helper function that formats and displays the current frequency. + */ + private void displayFreq() { + String a = Double.toString((double) mCurrentfrequency / 1000); + if (mFmBand.getChannelOffset() == CHANNEL_OFFSET_50KHZ) { + mFrequencyTextView.setText(String.format(a, "%.2f")); + } else { + mFrequencyTextView.setText(String.format(a, "%.1f")); + } + } + + /** + * Sets up the button animation + */ + private void setupAnimation() { + ImageView transmitImage = (ImageView) findViewById(R.id.TransmitIcon); + transmitImage.setBackgroundResource(R.drawable.anim); + mTransmitAnimation = (AnimationDrawable) transmitImage.getBackground(); + } + + /** + * Helper method to display toast + */ + private void showToast(final String text, final int duration) { + runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(getApplicationContext(), text, duration).show(); + } + }); + } + + /** + * Sets up the button's onclick listeners + */ + private void setupButtons() { + mFrequencyTextView = (TextView) findViewById(R.id.FrequencyTextView); + final Button tuneUp = (Button) findViewById(R.id.ScanUp); + tuneUp.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + try { + ((Button) findViewById(R.id.ScanUp)).setEnabled(false); + mFmTransmitter.setFrequency(mCurrentfrequency + mFrequencyIncrement); + } catch (Exception e) { + showToast("Unable to scan up", Toast.LENGTH_LONG); + return; + } + mCurrentfrequency += mFrequencyIncrement; + displayFreq(); + ((Button) findViewById(R.id.ScanUp)).setEnabled(true); + } + }); + final Button tuneDown = (Button) findViewById(R.id.ScanDown); + tuneDown.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + try { + ((Button) findViewById(R.id.ScanDown)).setEnabled(false); + mFmTransmitter.setFrequency(mCurrentfrequency - mFrequencyIncrement); + } catch (Exception e) { + showToast("Unable to scan down", Toast.LENGTH_LONG); + return; + } + mCurrentfrequency -= mFrequencyIncrement; + displayFreq(); + ((Button) findViewById(R.id.ScanDown)).setEnabled(true); + } + }); + final Button transmit = (Button) findViewById(R.id.Transmit); + transmit.setBackgroundResource(R.drawable.transmitgobutton); + transmit.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + switch (mFmTransmitter.getState()) { + + case FmTransmitter.STATE_IDLE: + try { + mFmTransmitter.startAsync(mFmBand); + showToast("Preparing radio", Toast.LENGTH_LONG); + } catch (Exception e) { + showToast("Unable to start radio", Toast.LENGTH_LONG); + return; + } + + break; + case FmTransmitter.STATE_PAUSED: + try { + mFmTransmitter.resume(); + } catch (Exception e) { + showToast("Unable to resume radio", Toast.LENGTH_LONG); + return; + } + mTransmitAnimation.start(); + transmit.setBackgroundResource(R.drawable.transmitstopbutton); + + break; + case FmTransmitter.STATE_STARTED: + try { + mFmTransmitter.pause(); + } catch (Exception e) { + showToast("Unable to pause radio", Toast.LENGTH_LONG); + return; + } + mTransmitAnimation.stop(); + transmit.setBackgroundResource(R.drawable.transmitgobutton); + break; + default: + } + } + }); + final Button blockscan = (Button) findViewById(R.id.BlockScan); + blockscan.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + blockscan(); + } + }); + } + + /** + * Sets up the options menu when the menu button is push, dynamic population + * of the station select menu + */ + public boolean onPrepareOptionsMenu(Menu menu) { + menu.clear(); + boolean result = super.onCreateOptionsMenu(menu); + SubMenu subMenu = menu.addSubMenu(BASE_OPTION_MENU, FM_BAND, Menu.NONE, + R.string.band_select); + subMenu.setIcon(android.R.drawable.ic_menu_mapmode); + // Populate the band selection menu + subMenu.add(BAND_SELECTION_MENU, BAND_US, Menu.NONE, R.string.band_us); + subMenu.add(BAND_SELECTION_MENU, BAND_EU, Menu.NONE, R.string.band_eu); + subMenu.add(BAND_SELECTION_MENU, BAND_CHINA, Menu.NONE, R.string.band_ch); + subMenu.add(BAND_SELECTION_MENU, BAND_JAPAN, Menu.NONE, R.string.band_ja); + subMenu.setGroupCheckable(BAND_SELECTION_MENU, true, true); + subMenu.getItem(mSelectedBand).setChecked(true); + return result; + } + + /** + * React to a selection in the option menu + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + if (item.getGroupId() == BAND_SELECTION_MENU) { + switch (item.getItemId()) { + case BAND_US: + mSelectedBand = FmBand.BAND_US; + item.setChecked(true); + break; + case BAND_EU: + mSelectedBand = FmBand.BAND_EU; + item.setChecked(true); + break; + case BAND_JAPAN: + mSelectedBand = FmBand.BAND_JAPAN; + item.setChecked(true); + break; + case BAND_CHINA: + mSelectedBand = FmBand.BAND_CHINA; + item.setChecked(true); + break; + default: + break; + } + mFmBand = new FmBand(mSelectedBand); + try { + mFmTransmitter.reset(); + ((Button) findViewById(R.id.Transmit)) + .setBackgroundResource(R.drawable.transmitgobutton); + ((TextView) findViewById(R.id.FrequencyTextView)).setText("----"); + mFrequencyIncrement = mFmBand.getChannelOffset() / 1000; + mTransmitAnimation.stop(); + } catch (Exception e) { + showToast("Unable to restart the FM Radio", Toast.LENGTH_LONG); + } + } + return super.onOptionsItemSelected(item); + } +} |
