Does ActionBarSherlock 4.2 support search suggestions for a SearchView? - java

A month ago, I dropped-in ActionBarSherlock 4.2 into my project. I got everything to work, except the search suggestions for my SearchView. The way I was creating search suggestions was using the method in the Android documentation.
Does ActionBarSherlock support search suggestions? I tried to dig through the issue list on the Github page but the issue seems closed but I can't seem to follow the discussion and understand whether it really is a resolved or not. I thought that some of you who've been using ActionBarSherlock might know better.

It doesn't. But I have found a way to make it query your ContentProvider.
I looked into the source of SuggestionsAdapter from API 17 where the query executes and got an idea of replacing this method. Also I found that ActionbarSherlock's SuggestionsAdapter does not use your SearchableInfo.
Edit com.actionbarsherlock.widget.SuggestionsAdapter in your ActionBarSherlock project:
Add a line
private SearchableInfo searchable;
in constructor, add
this.searchable = mSearchable;
Replace getSuggestions method with this one:
public Cursor getSuggestions(String query, int limit) {
if (searchable == null) {
return null;
}
String authority = searchable.getSuggestAuthority();
if (authority == null) {
return null;
}
Uri.Builder uriBuilder = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(authority)
.query("") // TODO: Remove, workaround for a bug in Uri.writeToParcel()
.fragment(""); // TODO: Remove, workaround for a bug in Uri.writeToParcel()
// if content path provided, insert it now
final String contentPath = searchable.getSuggestPath();
if (contentPath != null) {
uriBuilder.appendEncodedPath(contentPath);
}
// append standard suggestion query path
uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY);
// get the query selection, may be null
String selection = searchable.getSuggestSelection();
// inject query, either as selection args or inline
String[] selArgs = null;
if (selection != null) { // use selection if provided
selArgs = new String[] { query };
} else { // no selection, use REST pattern
uriBuilder.appendPath(query);
}
if (limit > 0) {
uriBuilder.appendQueryParameter("limit", String.valueOf(limit));
}
Uri uri = uriBuilder.build();
// finally, make the query
return mContext.getContentResolver().query(uri, null, selection, selArgs, null);
}
Now it queries my ContentProvider but crashes with default adapter saying that no layout_height loading some xml file from support library. So you have to use custom SuggestionsAdapter. This is what worked for me:
import com.actionbarsherlock.widget.SearchView;
import android.app.SearchManager;
import android.app.SearchableInfo;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public final class DrugsSearchAdapter extends CursorAdapter
{
private static final int QUERY_LIMIT = 50;
private LayoutInflater inflater;
private SearchView searchView;
private SearchableInfo searchable;
public DrugsSearchAdapter(Context context, SearchableInfo info, SearchView searchView)
{
super(context, null, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
this.searchable = info;
this.searchView = searchView;
this.inflater = LayoutInflater.from(context);
}
#Override
public void bindView(View v, Context context, Cursor c)
{
String name = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1));
TextView namet = (TextView) v.findViewById(R.id.list_item_drug_name);
namet.setText(name);
String man = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2));
TextView manuf = (TextView) v.findViewById(R.id.list_item_drug_manufacturer);
manuf.setText(man);
}
#Override
public View newView(Context arg0, Cursor arg1, ViewGroup arg2)
{
return this.inflater.inflate(R.layout.list_item_drug_search, null);
}
/**
* Use the search suggestions provider to obtain a live cursor. This will be called
* in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions).
* The results will be processed in the UI thread and changeCursor() will be called.
*/
#Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
String query = (constraint == null) ? "" : constraint.toString();
/**
* for in app search we show the progress spinner until the cursor is returned with
* the results.
*/
Cursor cursor = null;
if (searchView.getVisibility() != View.VISIBLE
|| searchView.getWindowVisibility() != View.VISIBLE) {
return null;
}
try {
cursor = getSuggestions(searchable, query, QUERY_LIMIT);
// trigger fill window so the spinner stays up until the results are copied over and
// closer to being ready
if (cursor != null) {
cursor.getCount();
return cursor;
}
} catch (RuntimeException e) {
}
// If cursor is null or an exception was thrown, stop the spinner and return null.
// changeCursor doesn't get called if cursor is null
return null;
}
public Cursor getSuggestions(SearchableInfo searchable, String query, int limit) {
if (searchable == null) {
return null;
}
String authority = searchable.getSuggestAuthority();
if (authority == null) {
return null;
}
Uri.Builder uriBuilder = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(authority)
.query("")
.fragment("");
// if content path provided, insert it now
final String contentPath = searchable.getSuggestPath();
if (contentPath != null) {
uriBuilder.appendEncodedPath(contentPath);
}
// append standard suggestion query path
uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY);
// get the query selection, may be null
String selection = searchable.getSuggestSelection();
// inject query, either as selection args or inline
String[] selArgs = null;
if (selection != null) { // use selection if provided
selArgs = new String[] { query };
} else { // no selection, use REST pattern
uriBuilder.appendPath(query);
}
if (limit > 0) {
uriBuilder.appendQueryParameter("limit", String.valueOf(limit));
}
Uri uri = uriBuilder.build();
// finally, make the query
return mContext.getContentResolver().query(uri, null, selection, selArgs, null);
}
}
And set this adapter in SearchView
searchView.setSuggestionsAdapter(new DrugsSearchAdapter(this, searchManager.getSearchableInfo(getComponentName()), searchView));

I'm the one that opened the github issue for this. It is working on the dev branch. The current version (4.2) doesn't have the fix. It was completely fixed by this commit, but I would suggest just checking out the dev branch and trying it.

I don't know if I'm wrong here or I changed something on accident, but the above answer does not work and the ActionBarSherlock SuggestionsAdapter does not work. All I get are null pointers in runQueryOnBackgroundThread. It never goes into bindView etc. either, yet it manages to display suggestion results. I think android.app.SearchManager is somehow overriding ABS with getSuggestions() but I'm not sure. I'm still trying things out...

Related

How to fix Asynctask error caused by Caused by: java.lang.NumberFormatException: For input string: "pets"

I'm getting this error:
​Caused by: java.lang.NumberFormatException: For input string: "pets" while trying to insert data into the database. While clicking on the insert option on the mainActivity it was supposed to insert data into the database and show that data into MainActivity but cuz of the error my application is getting crashed. How to solve this error? The error is caused in PetProvider query's Pet_ID at selection args point.
The code of PetProvider is shown below:
`2021-12-12 02:21:07.435 11934-11959/com.example.myapplication E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.example.myapplication, PID: 11934
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$4.done(AsyncTask.java:415)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by: java.lang.NumberFormatException: For input string: "pets"
at java.lang.Long.parseLong(Long.java:594)
at java.lang.Long.parseLong(Long.java:636)
at android.content.ContentUris.parseId(ContentUris.java:89)
at com.example.myapplication.data.PetProvider.query(PetProvider.java:100)
at android.content.ContentProvider.query(ContentProvider.java:1379)
at android.content.ContentProvider.query(ContentProvider.java:1475)
at android.content.ContentProvider$Transport.query(ContentProvider.java:278)
at android.content.ContentResolver.query(ContentResolver.java:1185)
at android.content.ContentResolver.query(ContentResolver.java:1116)
at android.content.CursorLoader.loadInBackground(CursorLoader.java:71)
at android.content.CursorLoader.loadInBackground(CursorLoader.java:46)
at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:321)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:74)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:62)
at android.os.AsyncTask$3.call(AsyncTask.java:394)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:923) 
package com.example.myapplication.data;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.nio.file.Path;
public class PetProvider extends ContentProvider {
private PetdbHepler petdbHepler;
public static String CONTENT_AUTHORITY = "com.example.myapplication";
//To make this a usable URI, we use the parse method which takes in a URI string and returns a Uri.
public static Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
//This constants stores the path for each of the tables which will be appended to the base content URI.
public static final String PATH_PETS = "pets";
public static final String LOG_TAG = PetProvider.class.getSimpleName();
/**
* URI matcher code for the content URI for the pets table
*/
private static final int PETS = 100;
/**
* URI matcher code for the content URI for a single pet in the pets table
*/
private static final int PET_ID = 101;
/**
* UriMatcher object to match a content URI to a corresponding code.
* The input passed into the constructor represents the code to return for the root URI.
* It's common to use NO_MATCH as the input for this case.
*/
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// Static initializer. This is run the first time anything is called from this class.
static {
// The calls to addURI() go here, for all of the content URI patterns that the provider
// should recognize. All paths added to the UriMatcher have a corresponding code to return
// when a match is found.
sUriMatcher.addURI(CONTENT_AUTHORITY, PATH_PETS, PETS);
sUriMatcher.addURI(CONTENT_AUTHORITY, PATH_PETS + "/#", PET_ID);
}
#Override
public boolean onCreate() {
petdbHepler = new PetdbHepler(getContext());
return false;
}
#Nullable
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, #Nullable String selection, #Nullable String[] selectionArgs, #Nullable String sortOrder) {
//steps To follow to query the database
//first we nedd to get access to the database
//second we need to pass the uri and check if the query is for whole table or for a single pet using uri matcher
//atlast we need to switch according to the uri
// so here is our code
SQLiteDatabase database = petdbHepler.getReadableDatabase(); /*since we are only querying the database we need to use
getReadableDatabase and this step is to access the database which is first step*/
Cursor cursor;
int matcher = sUriMatcher.match(uri);//second we need to pass the uri and check if the query is for whole table or for a single pet using uri matcher
switch (matcher) {
case PETS:
cursor = database.query(Petcontract.PetsEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
case PET_ID:
// For the PET_ID code, extract out the ID from the URI.
// For an example URI such as "content://com.example.android.pets/pets/3",
// the selection will be "_id=?" and the selection argument will be a
// String array containing the actual ID of 3 in this case.
//
// For every "?" in the selection, we need to have an element in the selection
// arguments that will fill in the "?". Since we have 1 question mark in the
// selection, we have 1 String in the selection arguments' String array.
selection = Petcontract.PetsEntry._ID + "?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
cursor = database.query(Petcontract.PetsEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
Log.e("PetProvider", "Hereis the problem");
break;
default:
throw new IllegalArgumentException("cannot query unknown uri" + uri);
}
// Set notification URI on the Cursor,
// so we know what content URI the Cursor was created for.
// If the data at this URI changes, then we know we need to update the Cursor
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Nullable
#Override
public String getType(#NonNull Uri uri) {
return null;
}
#Nullable
#Override
public Uri insert(#NonNull Uri uri, #Nullable ContentValues contentValues) {
final int match = sUriMatcher.match(uri);
switch (match) {
case PETS:
return insertPet(uri, contentValues);
default:
throw new IllegalArgumentException("Insertion is not supported for " + uri);
}
}
private Uri insertPet(Uri uri, ContentValues contentValues){
// Check that the name is not null
String name = contentValues.getAsString(Petcontract.PetsEntry.COLUMN_NAME);
if (name == null) {
throw new IllegalArgumentException("Pet requires a name");
}
// Check that the gender is valid
Integer gender = contentValues.getAsInteger(Petcontract.PetsEntry.COLUMN_GENDER);
if (gender == null) {
throw new IllegalArgumentException("Pet requires valid gender");
}
// If the weight is provided, check that it's greater than or equal to 0 kg
Integer weight = contentValues.getAsInteger(Petcontract.PetsEntry.COLUMN_WEIGHT);
if (weight != null && weight < 0) {
throw new IllegalArgumentException("Pet requires valid weight");
}
SQLiteDatabase sqLiteDatabase = petdbHepler.getWritableDatabase();
long id = sqLiteDatabase.insert(Petcontract.PetsEntry.TABLE_NAME, null, contentValues);
// Notify all listeners that the data has changed for the pet content URI
getContext().getContentResolver().notifyChange(uri, null);
return ContentUris.withAppendedId(Petcontract.PetsEntry.content_uri, id);
}
#Override
public int delete(#NonNull Uri uri, #Nullable String selection, #Nullable String[] selectionArgs) {
// Get writeable database
SQLiteDatabase database =petdbHepler.getWritableDatabase();
int rowsDeleted;
final int match = sUriMatcher.match(uri);
switch (match) {
case PETS:
// Delete all rows that match the selection and selection args
return database.delete(Petcontract.PetsEntry.TABLE_NAME, selection, selectionArgs);
case PET_ID:
// Delete a single row given by the ID in the URI
selection = Petcontract.PetsEntry._ID + "=?";
selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) };
rowsDeleted = database.delete(Petcontract.PetsEntry.TABLE_NAME, selection, selectionArgs);
// If 1 or more rows were deleted, then notify all listeners that the data at the
// given URI has changed
if (rowsDeleted != 0) {
getContext().getContentResolver().notifyChange(uri, null);
return database.delete(Petcontract.PetsEntry.TABLE_NAME, selection, selectionArgs);
}
else{
return rowsDeleted;
}
default:
throw new IllegalArgumentException("Deletion is not supported for " + uri);
}
}
#Override
public int update(#NonNull Uri uri, #Nullable ContentValues values, #Nullable String selection, #Nullable String[] selectionArgs) {
SQLiteDatabase database = petdbHepler.getWritableDatabase();
int rowsUpdated = database.update(Petcontract.PetsEntry.TABLE_NAME, values, selection, selectionArgs);
if (rowsUpdated != 0) {
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
else
{
return database.update(Petcontract.PetsEntry.TABLE_NAME, values, selection, selectionArgs);
}
}
}`
Just add break after the case: Pet. The code is;
case PETS:
cursor = database.query(Petcontract.PetsEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
break; //dont't forget to add break statement in Pet case.
case PET_ID:

Android : static String get Last Outgoing Call() method

I'd like to use the static String getLastOutgoingCall() method in order to pull the duration of the last outgoing phone call but I don't know how !
I'm a beginner with java programming (I usually program in c++)
The tutorials that I found use the ancient APIs and none of them use the method I'm talking about.
I hope I have not misinterpreted your question. If so, please let me know.
The method String getLastOutgoingCall (Context context) from android.provider.CallLog.Calls, according to the documentation, returns
The last phone number dialed (outgoing) or an empty string if none
exist yet.
So, you can't retrieve the last outgoing call duration using that method.
To get the last outgoing call duration, you can query the CallLog.Calls.CONTENT_URI to retrieve this info.
You can use a method like this:
public String getLastOutgoingCallDuration(final Context context) {
String output = null;
final Uri callog = CallLog.Calls.CONTENT_URI;
Cursor cursor = null;
try {
// Query all the columns of the records that matches "type=2"
// (outgoing) and orders the results by "date"
cursor = context.getContentResolver().query(callog, null,
CallLog.Calls.TYPE + "=" + CallLog.Calls.OUTGOING_TYPE,
null, CallLog.Calls.DATE);
final int durationCol = cursor
.getColumnIndex(CallLog.Calls.DURATION);
// Retrieve only the last record to get the last outgoing call
if (cursor.moveToLast()) {
// Retrieve only the duration column
output = cursor.getString(durationCol);
}
} finally {
// Close the resources
if (cursor != null) {
cursor.close();
}
}
return output;
}
Note: To perform this query you will need to add the following permission to your manifest:
<uses-permission android:name="android.permission.READ_CALL_LOG" />
Edit based on your own answer:
You need to call the getLastOutgoingCallDuration() on the onCreate() method of your Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); // Here you need to set the name of your xml
TextView displayDuration;
displayDuration = (TextView) findViewById(R.id.textView2);
String duration = getLastOutgoingCallDuration(this);
displayDuration.setText(output + "sec");
}

Query entities from google app engine using android

Ive tried a thousand things. As of right now the only way for me to query anything is to get the entire list and look through it that way! which takes way to much time. How can I query something in google app engine, for example pull only the entities that have > 100 votes for example.
Im following the tic-tac-toe example https://github.com/GoogleCloudPlatform/appengine-endpoints-tictactoe-java and https://developers.google.com/eclipse/docs/endpoints-addentities
In the example I just switched notes for quotes.
Heres my current code for example on how im getting the entities
this is an async task and its loading each one which takes to long
protected CollectionResponseQuotes doInBackground(Context... contexts) {
Quotesendpoint.Builder endpointBuilder = new Quotesendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) { }
});
Quotesendpoint endpoint = CloudEndpointUtils.updateBuilder(
endpointBuilder).build();
try {
quotes = endpoint.listquotes().execute();
for (Quotes quote : quotes.getItems()) {
if (quote.getVotes() > 3) {
quoteList.add(quote);
}
}
Here is the code that Google generated in the app engine for me when I created the endpoint. It looks like it will query somehow but I cant figure it out. They are two different projects.
#Api(name = "quotesendpoint", namespace = #ApiNamespace(ownerDomain = "projectquotes.com", ownerName = "projectquotes.com", packagePath = ""))
public class quotesEndpoint {
/**
* This method lists all the entities inserted in datastore.
* It uses HTTP GET method and paging support.
*
* #return A CollectionResponse class containing the list of all entities
* persisted and a cursor to the next page.
*/
#SuppressWarnings({ "unchecked", "unused" })
#ApiMethod(name = "listquotes")
public CollectionResponse<quotes> listquotes(
#Nullable #Named("cursor") String cursorString,
#Nullable #Named("limit") Integer limit) {
EntityManager mgr = null;
Cursor cursor = null;
List<quotes> execute = null;
try {
mgr = getEntityManager();
Query query = mgr.createQuery("select from quotes as quotes");
if (cursorString != null && cursorString != "") {
cursor = Cursor.fromWebSafeString(cursorString);
query.setHint(JPACursorHelper.CURSOR_HINT, cursor);
}
if (limit != null) {
query.setFirstResult(0);
query.setMaxResults(limit);
}
execute = (List<quotes>) query.getResultList();
cursor = JPACursorHelper.getCursor(execute);
if (cursor != null)
cursorString = cursor.toWebSafeString();
// Tight loop for fetching all entities from datastore and accomodate
// for lazy fetch.
for (quotes obj : execute)
;
} finally {
mgr.close();
}
return CollectionResponse.<quotes> builder().setItems(execute)
.setNextPageToken(cursorString).build();
}
/**
* This method gets the entity having primary key id. It uses HTTP GET method.
*
* #param id the primary key of the java bean.
* #return The entity with primary key id.
*/
#ApiMethod(name = "getquotes")
public quotes getquotes(#Named("id") String id) {
EntityManager mgr = getEntityManager();
quotes quotes = null;
try {
quotes = mgr.find(quotes.class, id);
} finally {
mgr.close();
}
return quotes;
}
Tried to user cursor but now sure how it works. Ive tried
Cursor cursor = db.rawQuery("select * from Votes WHERE Votes >" + 250 , null);
quotes = endpoint.listquotes().setCursor(cursor).execute();
Did you try to pass parameters to endpoint.listquotes()?
Specifically parameter "limit" to limit a number of results and parameter "cursor" to change selection criteria?

PreferenceFragment.findPreference always returns NULL

I'm currently trying to make a settings menu, that will show a MultiSelectListPreference, to select multiple contacts from your contact list.
At this moment, I'm receiving an NullPointerException, when i try to MultiSelectListPreference#setEntryValue(CharSequence[]) If I put the setEntries first, that one throws the same exception.
I've put a breakpoint, to see step by step what happens. The variables are filled because they store Strings, they can contain a String "null", so I guess that it doesn't fail if there is no Display_Name available or so.
I based the findPreference on the example of this answer
Anyone has an idea? If you need more information, tell me. Thanks for reading!
package be.wdk.sendtowork;contactNumberArray
import android.database.Cursor;
import android.os.Bundle;
import android.preference.MultiSelectListPreference;
import android.preference.PreferenceFragment;
import android.provider.ContactsContract;
import android.util.Log;
import android.widget.Toast;
public class PreferenceClass extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Integer countContacts = 0;
String[] projection = new String[]{
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.PHOTO_URI
};
String selection = ContactsContract.CommonDataKinds.Phone.HAS_PHONE_NUMBER;
String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME;
try {
Cursor c1 = getActivity().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, selection, null, sortOrder);
c1.moveToFirst();
Integer c1columncount = c1.getColumnCount();
Integer c1count = c1.getCount();
Toast toastje = Toast.makeText(getActivity(), c1columncount.toString() + " - " + c1count.toString(), Toast.LENGTH_SHORT);
toastje.show();
CharSequence[] contactNameArray = new CharSequence[c1count], contactNumberArray = new CharSequence[c1count];
MultiSelectListPreference mslp = (MultiSelectListPreference) findPreference("contactList");
do {
contactNameArray[countContacts] = c1.getString(0) + " - " + c1.getString(2);
contactNumberArray[countContacts] = c1.getString(1);
countContacts += 1;
} while(c1.moveToNext());
mslp.setEntryValues(contactNumberArray); //<- line that throws the error
mslp.setEntries(contactNameArray);
addPreferencesFromResource(R.xml.preferences);
}
catch (Exception e) {
Log.v("TAG", " " + e.toString());
e.getMessage();
}
}
}
EDIT: Ok, I did a couple more checks.
-I made a test preference in my XML and used the findPrefence to make an object of it to work with -> returns NULL
-I have set my key of my MultiSelectListPreference to #string/test, putted this in my strings.xml, findpreference still returns Null.
Can there be a problem with my PreferenceFragment?
Ok, i found what my problem was.
MultiSelectListPreference mslp = (MultiSelectListPreference) findPreference("contactList");
returns NULL because
addPreferencesFromResource(R.xml.preferences);
is not done at the start... so it didn't load my preferences in yet.
You can solve this using
getFragmentManager().executePendingTransactions();
before
findPreference(section);
In my case, I was trying to use findPreferences in onCreate of the enclosing PreferenceActivity. I moved it down to onCreate of the PreferenceFragment and it works fine.
You can solve this by placing the all the content access functions inside the following
fragment callback
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//Access the content here.
}

Send MMS from My application in android

I want to send MMS from my application to a specific number. I've searched and found this code but I have no idea if this code what I need or not.
My Questions is :
-can anyone explain this code to me.i am beginner in MMS.
-also, i thought this code is let the user send MMS from my application without move it to the native Messaging inbox (and this is what i want) Am i right?
-also i have a problem ,i do not know how can i put this code in my project.
this is what i found
MMS is just a http-post request. You should perform the request using extra network feature :
final ConnectivityManager connMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
final int result = connMgr.startUsingNetworkFeature( ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_MMS);
If you get back the result with Phone.APN_REQUEST_STARTED value, you have to wait for proper state. Register BroadCastReciver and wait until Phone.APN_ALREADY_ACTIVE appears:
final IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(reciver, filter);
If background connection is ready, then build content and perform request. If you want to do that using android's internal code, please use this:
final SendReq sendRequest = new SendReq();
final EncodedStringValue[] sub = EncodedStringValue.extract(subject);
if (sub != null && sub.length > 0) {
sendRequest.setSubject(sub[0]);
}
final EncodedStringValue[] phoneNumbers = EncodedStringValue.extract(recipient);
if (phoneNumbers != null && phoneNumbers.length > 0) {
sendRequest.addTo(phoneNumbers[0]);
}
final PduBody pduBody = new PduBody();
if (parts != null) {
for (MMSPart part : parts) {
final PduPart partPdu = new PduPart();
partPdu.setName(part.Name.getBytes());
partPdu.setContentType(part.MimeType.getBytes());
partPdu.setData(part.Data);
pduBody.addPart(partPdu);
}
}
sendRequest.setBody(pduBody);
final PduComposer composer = new PduComposer(this.context, sendRequest);
final byte[] bytesToSend = composer.make();
HttpUtils.httpConnection(context, 4444L, MMSCenterUrl, bytesToSendFromPDU, HttpUtils.HTTP_POST_METHOD, !TextUtils.isEmpty(MMSProxy), MMSProxy, port);
MMSCenterUrl: url from MMS-APNs,
MMSProxy: proxy from MMS-APNs,
port: port from MMS-APNs
Note that some classes are from internal packages. Download from android git is required.
The request should be done with url from user's apn-space code:
public class APNHelper {
public class APN {
public String MMSCenterUrl = "";
public String MMSPort = "";
public String MMSProxy = "";
}
public APNHelper(final Context context) {
this.context = context;
}
public List<APN> getMMSApns() {
final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"), null, null, null, null);
if ( apnCursor == null ) {
return Collections.EMPTY_LIST;
} else {
final List<APN> results = new ArrayList<APN>();
while ( apnCursor.moveToNext() ) {
final String type = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.TYPE));
if ( !TextUtils.isEmpty(type) && ( type.equalsIgnoreCase(Phone.APN_TYPE_ALL) || type.equalsIgnoreCase(Phone.APN_TYPE_MMS) ) ) {
final String mmsc = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.MMSC));
final String mmsProxy = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.MMSPROXY));
final String port = apnCursor.getString(apnCursor.getColumnIndex(Telephony.Carriers.MMSPORT));
final APN apn = new APN();
apn.MMSCenterUrl = mmsc;
apn.MMSProxy = mmsProxy;
apn.MMSPort = port;
results.add(apn);
}
}
apnCursor.close();
return results;
}
Please help me
why don't you use the android system functions:
Please have a look on
https://developer.android.com/guide/components/intents-common.html
public void composeMmsMessage(String message, Uri attachment) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setData(Uri.parse("smsto:")); // This ensures only SMS apps respond
intent.putExtra("sms_body", message);
intent.putExtra(Intent.EXTRA_STREAM, attachment);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent); }
}
Cheers
Tom
I found a link in an other thread to a github project that works 100% https://github.com/klinker41/android-smsmms
Notice, that obligatory settings are only
Settings sendSettings = new Settings();
sendSettings.setMmsc(mmsc);
sendSettings.setProxy(proxy);
sendSettings.setPort(port);
you can get them something like (found at Set APN programmatically on Android - answear by vincent091):
Cursor cursor = null;
if (Utils.hasICS()){
cursor =SqliteWrapper.query(activity, activity.getContentResolver(),
Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), APN_PROJECTION, null, null, null);
} else {
cursor = activity.getContentResolver().query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"),
null, null, null, null);
}
cursor.moveToLast();
String type = cursor.getString(cursor.getColumnIndex(Telephony.Carriers.TYPE));
String mmsc = cursor.getString(cursor.getColumnIndex(Telephony.Carriers.MMSC));
String proxy = cursor.getString(cursor.getColumnIndex(Telephony.Carriers.MMSPROXY));
String port = cursor.getString(cursor.getColumnIndex(Telephony.Carriers.MMSPORT));

Categories