1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.smssample; 18 19 import android.content.Intent; 20 import android.database.Cursor; 21 import android.net.Uri; 22 import android.os.Bundle; 23 import android.provider.Telephony.Sms.Inbox; 24 import android.support.v4.app.FragmentActivity; 25 import android.support.v4.app.LoaderManager.LoaderCallbacks; 26 import android.support.v4.content.CursorLoader; 27 import android.support.v4.content.Loader; 28 import android.support.v4.widget.SimpleCursorAdapter; 29 import android.text.TextUtils; 30 import android.view.Menu; 31 import android.view.View; 32 import android.view.View.OnClickListener; 33 import android.widget.Button; 34 import android.widget.EditText; 35 import android.widget.ListView; 36 import android.widget.RelativeLayout; 37 import android.widget.Toast; 38 39 /** 40 * The main Activity that provides a sample of a few things: 41 * -detecting if this app is the default SMS app and then showing/hiding UI and enabling/disabling 42 * functionality. the UI that is shown has a button to prompt the user to set this app as the 43 * default. 44 * -a simple query to the SMS content provider to show a list of SMS messages in the inbox. even 45 * though the query uses KitKat APIs this query should still work on earlier versions of Android 46 * as the contract class and ContentProvider were still around (with essentially the same 47 * structure) but were private. 48 * -being triggered from another application when creating a new SMS. a good example is creating 49 * a new SMS from the system People application. although nothing is done with the incoming 50 * Intent in this case (just a Toast is displayed) 51 * 52 * Obviously this is far from a full implementation and should just be used as a sample of how 53 * an app could be set up to correctly integrate with the new Android 4.4 KitKat APIs while 54 * running normally on earlier Android versions. 55 */ 56 public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor> { 57 private RelativeLayout mSetDefaultSmsLayout; 58 private Button mSendSmsButton; 59 private EditText mSendSmsEditText; 60 private SimpleCursorAdapter mAdapter; 61 62 @Override 63 protected void onCreate(Bundle savedInstanceState) { 64 super.onCreate(savedInstanceState); 65 setContentView(R.layout.activity_main); 66 67 // Find some views 68 mSetDefaultSmsLayout = (RelativeLayout) findViewById(R.id.set_default_sms_layout); 69 mSendSmsEditText = (EditText) findViewById(R.id.send_sms_edittext); 70 ListView listView = (ListView) findViewById(android.R.id.list); 71 listView.setEmptyView(findViewById(android.R.id.empty)); 72 mSendSmsButton = (Button) findViewById(R.id.send_sms_button); 73 mSendSmsButton.setOnClickListener(new OnClickListener() { 74 @Override 75 public void onClick(View view) { 76 sendSms(mSendSmsEditText.getText().toString()); 77 } 78 }); 79 80 // Create adapter and set it to our ListView 81 final String[] fromFields = new String[] { 82 SmsQuery.PROJECTION[SmsQuery.ADDRESS], SmsQuery.PROJECTION[SmsQuery.BODY] }; 83 final int[] toViews = new int[] { android.R.id.text1, android.R.id.text2 }; 84 mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null, 85 fromFields, toViews, 0); 86 listView.setAdapter(mAdapter); 87 88 // Placeholder to process incoming SEND/SENDTO intents 89 String intentAction = getIntent() == null ? null : getIntent().getAction(); 90 if (!TextUtils.isEmpty(intentAction) && (Intent.ACTION_SENDTO.equals(intentAction) 91 || Intent.ACTION_SEND.equals(intentAction))) { 92 // TODO: Handle incoming SEND and SENDTO intents by pre-populating UI components 93 Toast.makeText(this, "Handle SEND and SENDTO intents: " + getIntent().getDataString(), 94 Toast.LENGTH_SHORT).show(); 95 } 96 97 // Simple query to show the most recent SMS messages in the inbox 98 getSupportLoaderManager().initLoader(SmsQuery.TOKEN, null, this); 99 } 100 101 /** 102 * Dummy sendSms method, would need the "to" address to actually send a message :) 103 */ 104 private void sendSms(String smsText) { 105 if (!TextUtils.isEmpty(smsText)) { 106 if (Utils.isDefaultSmsApp(this)) { 107 // TODO: Use SmsManager to send SMS and then record the message in the system SMS 108 // ContentProvider 109 Toast.makeText(this, "Sending text message: " + smsText, Toast.LENGTH_SHORT).show(); 110 } else { 111 // TODO: Notify the user the app is not default and provide a way to trigger 112 // Utils.setDefaultSmsApp() so they can set it. 113 Toast.makeText(this, "Not default", Toast.LENGTH_SHORT).show(); 114 } 115 } 116 } 117 118 @Override 119 protected void onResume() { 120 super.onResume(); 121 122 // Only do these checks/changes on KitKat+, the "mSetDefaultSmsLayout" has its visibility 123 // set to "gone" in the xml layout so it won't show at all on earlier Android versions. 124 if (Utils.hasKitKat()) { 125 if (Utils.isDefaultSmsApp(this)) { 126 // This app is the default, remove the "make this app the default" layout and 127 // enable message sending components. 128 mSetDefaultSmsLayout.setVisibility(View.GONE); 129 mSendSmsEditText.setHint(R.string.sms_send_new_hint); 130 mSendSmsEditText.setEnabled(true); 131 mSendSmsButton.setEnabled(true); 132 } else { 133 // Not the default, show the "make this app the default" layout and disable 134 // message sending components. 135 mSetDefaultSmsLayout.setVisibility(View.VISIBLE); 136 mSendSmsEditText.setText(""); 137 mSendSmsEditText.setHint(R.string.sms_send_disabled); 138 mSendSmsEditText.setEnabled(false); 139 mSendSmsButton.setEnabled(false); 140 141 Button button = (Button) findViewById(R.id.set_default_sms_button); 142 button.setOnClickListener(new OnClickListener() { 143 @Override 144 public void onClick(View view) { 145 Utils.setDefaultSmsApp(MainActivity.this); 146 } 147 }); 148 } 149 } 150 } 151 152 @Override 153 public boolean onCreateOptionsMenu(Menu menu) { 154 // Inflate the menu; this adds items to the action bar if it is present. 155 getMenuInflater().inflate(R.menu.main, menu); 156 return true; 157 } 158 159 @Override 160 public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { 161 if (i == SmsQuery.TOKEN) { 162 // This will fetch all SMS messages in the inbox, ordered by date desc 163 return new CursorLoader(this, SmsQuery.CONTENT_URI, SmsQuery.PROJECTION, null, null, 164 SmsQuery.SORT_ORDER); 165 } 166 return null; 167 } 168 169 @Override 170 public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { 171 if (cursorLoader.getId() == SmsQuery.TOKEN && cursor != null) { 172 // Standard swap cursor in when load is done 173 mAdapter.swapCursor(cursor); 174 } 175 } 176 177 @Override 178 public void onLoaderReset(Loader<Cursor> cursorLoader) { 179 // Standard swap cursor to null when loader is reset 180 mAdapter.swapCursor(null); 181 } 182 183 /** 184 * A basic SmsQuery on android.provider.Telephony.Sms.Inbox 185 */ 186 private interface SmsQuery { 187 int TOKEN = 1; 188 189 static final Uri CONTENT_URI = Inbox.CONTENT_URI; 190 191 static final String[] PROJECTION = { 192 Inbox._ID, 193 Inbox.ADDRESS, 194 Inbox.BODY, 195 }; 196 197 static final String SORT_ORDER = Inbox.DEFAULT_SORT_ORDER; 198 199 int ID = 0; 200 int ADDRESS = 1; 201 int BODY = 2; 202 } 203 } 204