I am working on Dibs Payment integration but unable to achieve success. All things are working good in demo mode but when merchant id is supplied to it then before opening card details form it gives an error "Data has been tampered. Checksome is not valid". I dont know what is it. After my googling i found it is something related to MAC calculated but how to calculate MAC in my code. My whole class for payment is as follows with all comments.
public class CheckOut extends Activity {
private static final String TAG = "DIBS." + CheckOut.class.getSimpleName();
private DibsPayment paymentWindow;
public static String total, resname, resid, userid, menunames, itemnames,
itemquantity, ordertype, address, city, contactno, pincode,
deliverttime, orderid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.checkout);
RandomStringGenerator randomorderid = new RandomStringGenerator();
Intent i = getIntent();
// total=String.valueOf(1);
total = i.getStringExtra("grandTotal");
resname = i.getStringExtra("res_name");
resid = i.getStringExtra("res_id");
userid = i.getStringExtra("user_id");
menunames = i.getStringExtra("menu_names");
itemnames = i.getStringExtra("item_prices");
itemquantity = i.getStringExtra("item_quantity");
ordertype = i.getStringExtra("ordertype");
address = i.getStringExtra("address");
city = i.getStringExtra("city");
contactno = i.getStringExtra("phone");
pincode = i.getStringExtra("pin");
deliverttime = i.getStringExtra("delivery_time");
orderid = randomorderid.getAlphaNumeric(5);
Toast.makeText(
getApplicationContext(),
orderid + "\n" + resname + "\n" + resid + "\n" + userid + "\n"
+ ordertype + "\n" + address + "\n" + city + "\n"
+ pincode + "\n" + contactno + "\n" + deliverttime
+ "\n" + menunames + "\n" + itemnames + "\n"
+ itemquantity + "\n" + total, Toast.LENGTH_SHORT)
.show();
/*
* Intent intent=getIntent(); String []
* arrayList=intent.getStringArrayExtra("payment_item"); // int l_itr =
* arrayList.length; // while(l_itr.hasNext()) { for(int
* i=0;i<=arrayList.length-1;i++){
*
* #SuppressWarnings("rawtypes") //HashMap l_map = (HashMap)
* l_itr.next(); String item=arrayList[i]; Log.v(item, "item"); String
* item =(String)i.get(DatabaseHandler.KEY_ITEM); Log.v(item, "item");
* String unicost= (String)l_map.get(DatabaseHandler.KEY_UNITCOST);
* Log.v(unicost, "unicost"); String l_res_name = (String)
* l_map.get(DatabaseHandler.KEY_QUANTITY); Log.v(l_res_name,
* "quantity"); String l_street = (String)
* l_map.get(DatabaseHandler.KEY_TOTAL); Log.v(l_street, "total"); }
*/
paymentWindow = (DibsPayment) findViewById(R.id.DibsPayment);
// Set your listener implementation, to get callbacks in the life-cycle
// of a payment processing
paymentWindow
.setPaymentResultListener(new MyPaymentResultListener(this));
// Load the payment window with the payment data that suits the payment
// flow you need
// Please be patient, when loading on the emulator
paymentWindow.loadPaymentWindow(constructPaymentData());
}
/**
* Shows a "cancel" action in the options menu on the phone, which shows how
* to call cancel functionality into the payment window to cancel ongoing
* payment processing.
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.payment_window_menu, menu);
return true;
}
/**
* If user chose "cancel" in options menu, we call "cancel" into payment
* window.
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menuitem_payment_window_cancel:
//
// Calling cancel into payment window cancels the ongoing payment
// processing.
// Because cancelling is an asynchronous process, you will need to
// wait for a callback
// to paymentCancelled on your PaymentResultListener listener,
// before being positive that
// payment window is done cancelling.
//
paymentWindow.cancelPayment();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* #return the payment data instance that is needed as input to
* {#link DibsPayment#loadPaymentWindow(dk.dibs.android.library.PaymentData)}
*/
private PaymentData constructPaymentData() {
// IMPORTANT: This needs to be set to YOUR merchant number, that you
// have obtained through an
// agreement with DIBS.
// you can use the merchant "demo" for a demorun through the payment
// window // read information about demo mode in the documentation
String merchantId = "******";
//String merchantId = "demo";
// The currency the payment is to be processed in
String currencyCode = "DKK";
// You set this to your own orderId value
String yourOrderId = orderid;
// The amount to be paid, given in "least possible unit" (aka: "oerer")
long amount = (new Double(total)).longValue();
// The cards that is allowed to be used in payment window
List<String> payTypes = new ArrayList<String>();
payTypes.add("MC");
payTypes.add("MTRO");
payTypes.add("VISA");
// this will add fee to the payment window.
boolean calcfee = true;
// In this example, we simply use "PurchasePaymentData", which is a
// simple "buy-with-credit-card" flow,
// where no pre-authorization is performed.
//
// Look to other subclasses of PaymentData for the other supported
// flows.
//
PurchasePaymentData paymentData = new PurchasePaymentData(merchantId,
currencyCode, yourOrderId, amount, payTypes);
paymentData.setCalcfee(calcfee);
// Set this flag to "true", if you want to be able to use test cards.
// REMEMBER to reset this to false, in production !!!
paymentData.setTest(true);
// If you want checks (and payment failure) if the orderId you gave
// already have been payed.
paymentData.setUseUniqueOrderIdCheck(false);
// If you want MAC security calculations, you will need to pre-calculate
// a MAC value on your server,
// based on the values you give to this payment window, and set this
// pre-calculated MAC value like this.
//
paymentData.setCalculatedMAC("");
// Payment window supports loading cancel or callback URLs based on
// payment outcome.
// Another, and maybe better, way to do this in an app, is to listen for
// the proper callbacks
// on the listener you set on the payment window, and then do your own
// cancel or payment success
// handling against your own servers.
//
try {
paymentData.setCallbackUrl(new URL(
"http://****.demoprojects.in/accept.php"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
paymentData.setCancelUrl(new URL("http://****.demoprojects.in/accept.php"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
paymentData.setLanguage("en_UK");
paymentData.setTheme(Theme.ANDROID_DIBS);
// If you need to, you can pass custom options to the payment window,
// which will be posted back again.
//
// Map<String, String> yourCustomOptions = new HashMap<String,
// String>();
// yourCustomOptions.put("foo", "bar");
// paymentData.setCustomOptions(yourCustomOptions);
return paymentData;
}
/*
* public void delete() { DatabaseHandler readDatabase = new
* DatabaseHandler( getApplicationContext()); readDatabase.deleteAll(); }
*/
}
This is the first time i am working on payment. Please help me out as security is the main concern here.
Thanks in advance :)
Dibs allow MAC to be calculated by two algorithms The choice of algorithm is up to you. It currently handles MD5 and SHA-1. SHA-1 is recommended by Dibs as it provides better security.
SHA-1(data¤cy&method&SecretKey&)
or
MD5(data¤cy&method&SecretKey&)
data here is the string containing information regarding the amount and quantity of purchase.
Security > DebiTech DefenderTM > MAC Configuration, here you will find the secret key in dibs dashboard.
Click here for further reference:
Related
From what I have read so far, it seems that there is no way to style Google Maps via the Android API.
Has anyone seen differently or know a way to style Google Maps on Android (change feature colors, etc.)?
From what I have seen, the only alternative to a full map library for Android (or iOS) is Mapbox, but their Android library is still under heavy development.
Google introduced Cloud-based Map Styling (however it is in Beta now). Using this feature, it is possible to set up a Map Id and a Map Style in Google Cloud Platform and to use it in the Android App (the only thing you need to do in the app is to specify the Map Id).
Here are the details:
https://developers.google.com/maps/documentation/android-sdk/cloud-based-map-styling
PS Here is the description of the 'old' option where you need to create a special json file and use it in the Android app to get a styled map:
https://developers.google.com/maps/documentation/android-sdk/styling
We can create styled maps as follows in android:
StyledMapDemoActivity.java
public class StyledMapDemoActivity extends AppCompatActivity implements OnMapReadyCallback {
private GoogleMap mMap = null;
private static final String TAG = StyledMapDemoActivity.class.getSimpleName();
private static final String SELECTED_STYLE = "selected_style";
// Stores the ID of the currently selected style, so that we can re-apply it when
// the activity restores state, for example when the device changes orientation.
private int mSelectedStyleId = R.string.style_label_default;
// These are simply the string resource IDs for each of the style names. We use them
// as identifiers when choosing which style to apply.
private int mStyleIds[] = {
R.string.style_label_retro,
R.string.style_label_night,
R.string.style_label_grayscale,
R.string.style_label_no_pois_no_transit,
R.string.style_label_default,
};
private static final LatLng SYDNEY = new LatLng(-33.8688, 151.2093);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mSelectedStyleId = savedInstanceState.getInt(SELECTED_STYLE);
}
setContentView(R.layout.styled_map_demo);
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onSaveInstanceState(Bundle outState) {
// Store the selected map style, so we can assign it when the activity resumes.
outState.putInt(SELECTED_STYLE, mSelectedStyleId);
super.onSaveInstanceState(outState);
}
#Override
public void onMapReady(GoogleMap map) {
mMap = map;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, 14));
setSelectedStyle();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.styled_map, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_style_choose) {
showStylesDialog();
}
return true;
}
/**
* Shows a dialog listing the styles to choose from, and applies the selected
* style when chosen.
*/
private void showStylesDialog() {
// mStyleIds stores each style's resource ID, and we extract the names here, rather
// than using an XML array resource which AlertDialog.Builder.setItems() can also
// accept. We do this since using an array resource would mean we would not have
// constant values we can switch/case on, when choosing which style to apply.
List<String> styleNames = new ArrayList<>();
for (int style : mStyleIds) {
styleNames.add(getString(style));
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.style_choose));
builder.setItems(styleNames.toArray(new CharSequence[styleNames.size()]),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
mSelectedStyleId = mStyleIds[which];
String msg = getString(R.string.style_set_to, getString(mSelectedStyleId));
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT).show();
Log.d(TAG, msg);
setSelectedStyle();
}
});
builder.show();
}
/**
* Creates a {#link MapStyleOptions} object via loadRawResourceStyle() (or via the
* constructor with a JSON String), then sets it on the {#link GoogleMap} instance,
* via the setMapStyle() method.
*/
private void setSelectedStyle() {
MapStyleOptions style;
switch (mSelectedStyleId) {
case R.string.style_label_retro:
// Sets the retro style via raw resource JSON.
style = MapStyleOptions.loadRawResourceStyle(this, R.raw.mapstyle_retro);
break;
case R.string.style_label_night:
// Sets the night style via raw resource JSON.
style = MapStyleOptions.loadRawResourceStyle(this, R.raw.mapstyle_night);
break;
case R.string.style_label_grayscale:
// Sets the grayscale style via raw resource JSON.
style = MapStyleOptions.loadRawResourceStyle(this, R.raw.mapstyle_grayscale);
break;
case R.string.style_label_no_pois_no_transit:
// Sets the no POIs or transit style via JSON string.
style = new MapStyleOptions("[" +
" {" +
" \"featureType\":\"poi.business\"," +
" \"elementType\":\"all\"," +
" \"stylers\":[" +
" {" +
" \"visibility\":\"off\"" +
" }" +
" ]" +
" }," +
" {" +
" \"featureType\":\"transit\"," +
" \"elementType\":\"all\"," +
" \"stylers\":[" +
" {" +
" \"visibility\":\"off\"" +
" }" +
" ]" +
" }" +
"]");
break;
case R.string.style_label_default:
// Removes previously set style, by setting it to null.
style = null;
break;
default:
return;
}
mMap.setMapStyle(style);
}
}
StyledMapDemoActivity.xml
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
I've got a rating bar in my android application which is in a custom adapter. I've set the ratingbar to listen for a change and on that change, update the database through a cient/server architecture. I then use the custom adapter in a master/details view. The problem is, everytime I load the details page on click of the left-hand list item, it updates the rating bar. This is not what I want. I only want to update the rating bar once it's been clicked, not everytime the adapter is used.
Is there way to only fire an event when it is clicked and not changed. Is there a major difference between onratingbarchanged (which it is currently) and onratingbarclicked (which I'm assuming is what I should be doing?)
My code is as follows:
//Should this rather be setOnClickListener()???
ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener()
{
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser)
{
questions.get(position).TotalRating = rating;
String newRating = "" + rating;
ratingBar.setRating(rating);
Toast.makeText(getContext(),
"Rating set to: " + rating + " for the position: " + position, Toast.LENGTH_SHORT).show();
String question = questions.get(position).Question;
//Create XML with both position/question to send to doAsyncTask
serverUpdateRating update = new serverUpdateRating();
Document doc;
try
{
//Create an XML document with question from the selected position as well as the new rating
doc = x.createDoc();
Element tutor = doc.createElement("Update");
tutor.appendChild(x.UpdateRating(doc, newRating, question));
doc.appendChild(tutor);
//Create a string
String s = x.getStringFromDocument(doc);
String result = update.execute(s).get();
//return either true (updated correctly) or false (problem)
if (result.equals("true"))
{
Toast.makeText(getContext(),
"Rating successfully updated", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(getContext(),
"Rating update unsuccessful", Toast.LENGTH_LONG).show();
}
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
I don't know if there is a workaround for this, but if there is, I would be extremely grateful!
You could use fromUser in onRatingChanged
onRatingChanged :
[...] fromUser True if the rating change was initiated by a user's touch
gesture or arrow key/horizontal trackbell movement.
I have an application in which on clicking a button, or on changing place, or after a particular time, I am able to get longitude and latitude values. I want to use this values to show them on Google Map application. I am opening a map using intent to show location, but somehow its not showing cordinates which I am getting.
This is a working piece of code that I use in one of my apps. This code also includes a check to find out if the user has Google Maps installed on his / her device. If the check returns the app as installed, then the function will pass on the data to the app. If the check fails, it displays an AlertDialog informing the use that the app is not installed.
protected void showMap() {
boolean installedMaps = false;
// CHECK IF GOOGLE MAPS IS INSTALLED
PackageManager pkManager = getPackageManager();
try {
#SuppressWarnings("unused")
PackageInfo pkInfo = pkManager.getPackageInfo("com.google.android.apps.maps", 0);
installedMaps = true;
} catch (Exception e) {
e.printStackTrace();
installedMaps = false;
}
// SHOW THE MAP USING CO-ORDINATES FROM THE CHECKIN
if (installedMaps == true) {
String geoCode = "geo:0,0?q=" + PLACE_LATITUDE + ","
+ PLACE_LONGITUDE + "(" + PLACE_NAME + ")";
Intent sendLocationToMap = new Intent(Intent.ACTION_VIEW,
Uri.parse(geoCode));
startActivity(sendLocationToMap);
} else if (installedMaps == false) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
CheckinsDetails.this);
// SET THE ICON
alertDialogBuilder.setIcon(R.drawable.ic_launcher);
// SET THE TITLE
alertDialogBuilder.setTitle("Google Maps Not Found");
// SET THE MESSAGE
alertDialogBuilder
.setMessage(R.string.noMapsInstalled)
.setCancelable(false)
.setNeutralButton("Got It",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int id) {
dialog.dismiss();
}
});
// CREATE THE ALERT DIALOG
AlertDialog alertDialog = alertDialogBuilder.create();
// SHOW THE ALERT DIALOG
alertDialog.show();
}
}
This line of code mentioned below sends it to Google Maps and instead of displaying just the Pin also displays the location name.
String geoCode = "geo:0,0?q=" + PLACE_LATITUDE + ","
+ PLACE_LONGITUDE + "(" + PLACE_NAME + ")";
EDIT: If you do not wish to display the PLACE_NAME, modify that particular line with: geo:latitude,longitude instead of the one used in the code block.
Check this link for further combinations possible, like zoom for example: http://developer.android.com/guide/appendix/g-app-intents.html
Double latitud = 37.40*1E6;
Double longitud = -5.99*1E6;
GeoPoint loc =
new GeoPoint(latitud.intValue(), longitud.intValue());
controlMapa.animateTo(loc);
int zoomActual = mapa.getZoomLevel();
for(int i=zoomActual; i<10; i++)
controlMapa.zoomIn();
}
where
controlMapa = mapa.getController();
mapa = (MapView)findViewById(R.id.linearLayout1);
For more info: MapView Tutorial
try this:
String url = "http://maps.google.com/maps?daddr="+ ze.getCoordenada().getLatitude() + ","+ ze.getCoordenada().getLongitude();
Intent goZe = new Intent(Intent.ACTION_VIEW);
goZe.setData(Uri.parse(url));
startActivity(goZe);
you will get a prompt to use browser or Maps
somehow, using this string on google
String url = "http://maps.google.com/maps?daddr="+ ze.getCoordenada().getLatitude() + ","+ ze.getCoordenada().getLongitude();
while selecting google maps shows oposite longitude and latitude while the website is correct.
maybe i am using an old version of google maps
public void showMap(long latitude, long longitude) {
String geoCode = "geo:0,0?q=" + latitude + ","
+ longitude;
Intent sendLocationToMap = new Intent(Intent.ACTION_VIEW, Uri.parse(geoCode));
if (sendLocationToMap.resolveActivity(getPackageManager())!=null){
startActivity(sendLocationToMap);
}
else {
Toast.makeText(this,"No Application To handle the Request",Toast.LENGTH_SHORT).show();
}
}
I've seen apps doing this, but I don't have a clue where to start. Any hints? Some code snippets will be appreciated.
/**
* Add a bookmark to the database.
*
* #param context
* Context of the calling Activity. This is used to make Toast confirming that the bookmark has been added. If the caller provides null, the Toast will not be shown.
* #param cr
* The ContentResolver being used to add the bookmark to the db.
* #param url
* URL of the website to be bookmarked.
* #param name
* Provided name for the bookmark.
* #param thumbnail
* A thumbnail for the bookmark.
* #param retainIcon
* Whether to retain the page's icon in the icon database. This will usually be <code>true</code> except when bookmarks are added by a settings restore agent.
*/
static void addBookmark(Context context, ContentResolver cr, String url, String name, Bitmap thumbnail, boolean retainIcon) {
final String WHERE_CLAUSE = "url = ? OR url = ? OR url = ? OR url = ?";
final String WHERE_CLAUSE_SECURE = "url = ? OR url = ?";
String[] SELECTION_ARGS;
// Want to append to the beginning of the list
long creationTime = new Date().getTime();
// First we check to see if the user has already visited this
// site. They may have bookmarked it in a different way from
// how it's stored in the database, so allow different combos
// to map to the same url.
boolean secure = false;
String compareString = url;
if (compareString.startsWith("http://")) {
compareString = compareString.substring(7);
} else if (compareString.startsWith("https://")) {
compareString = compareString.substring(8);
secure = true;
}
if (compareString.startsWith("www.")) {
compareString = compareString.substring(4);
}
if (secure) {
SELECTION_ARGS = new String[2];
SELECTION_ARGS[0] = "https://" + compareString;
SELECTION_ARGS[1] = "https://www." + compareString;
} else {
SELECTION_ARGS = new String[4];
SELECTION_ARGS[0] = compareString;
SELECTION_ARGS[1] = "www." + compareString;
SELECTION_ARGS[2] = "http://" + compareString;
SELECTION_ARGS[3] = "http://" + SELECTION_ARGS[1];
}
Cursor cursor = cr.query(Browser.BOOKMARKS_URI, Browser.HISTORY_PROJECTION, secure ? WHERE_CLAUSE_SECURE : WHERE_CLAUSE, SELECTION_ARGS, null);
ContentValues map = new ContentValues();
if (cursor.moveToFirst() && cursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX) == 0) {
// This means we have been to this site but not bookmarked
// it, so convert the history item to a bookmark
map.put(Browser.BookmarkColumns.CREATED, creationTime);
map.put(Browser.BookmarkColumns.TITLE, name);
map.put(Browser.BookmarkColumns.BOOKMARK, 1);
// map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
cr.update(Browser.BOOKMARKS_URI, map, "_id = " + cursor.getInt(0), null);
} else {
int count = cursor.getCount();
boolean matchedTitle = false;
for (int i = 0; i < count; i++) {
// One or more bookmarks already exist for this site.
// Check the names of each
cursor.moveToPosition(i);
if (cursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX).equals(name)) {
// The old bookmark has the same name.
// Update its creation time.
map.put(Browser.BookmarkColumns.CREATED, creationTime);
cr.update(Browser.BOOKMARKS_URI, map, "_id = " + cursor.getInt(0), null);
matchedTitle = true;
break;
}
}
if (!matchedTitle) {
// Adding a bookmark for a site the user has visited,
// or a new bookmark (with a different name) for a site
// the user has visited
map.put(Browser.BookmarkColumns.TITLE, name);
map.put(Browser.BookmarkColumns.URL, url);
map.put(Browser.BookmarkColumns.CREATED, creationTime);
map.put(Browser.BookmarkColumns.BOOKMARK, 1);
map.put(Browser.BookmarkColumns.DATE, 0);
// map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
int visits = 0;
if (count > 0) {
// The user has already bookmarked, and possibly
// visited this site. However, they are creating
// a new bookmark with the same url but a different
// name. The new bookmark should have the same
// number of visits as the already created bookmark.
visits = cursor.getInt(Browser.HISTORY_PROJECTION_VISITS_INDEX);
}
// Bookmark starts with 3 extra visits so that it will
// bubble up in the most visited and goto search box
map.put(Browser.BookmarkColumns.VISITS, visits + 3);
cr.insert(Browser.BOOKMARKS_URI, map);
}
}
if (retainIcon) {
WebIconDatabase.getInstance().retainIconForPageUrl(url);
}
cursor.close();
}
You can see the OS code here
I want to create a bookmark in the stock android-browser from my own application. How can I do this?
I only found the Browser.saveBookmark-Method (api-doc) but this displays a new window where the user can change the data. As I want to import bookmarks from a external data-source I want to save the bookmark directly and not ask the user for input.
If you just want to allow the user to add a bookmark, android.provider.Browser.saveBookmark() is what you want. But it looks like you're wanting to do mass updates, so that's probably not enough since it just opens the browser's bookmarks page.
AFAIK there is no open API that ties directly into the browser's bookmarks. However, there is a content resolver for it which can be accessed android.provider.Browser.BOOKMARKS_URI. Once you've resolved the provider you can manipulate bookmarks by running queries, provided you have the com.android.browser.permission.READ_HISTORY_BOOKMARKS and com.android.browser.permission.WRITE_HISTORY_BOOKMARKS permissions.
If you're unfamiliar with content providers, they can get kinda hairy (doubly so if you're unfamiliar with SQL). However, the knowledge base has some good articles on them, and a quick google for "android content provider tutorial" should get you well on your way.
I took the following code from Android implementation (and disabled the "bookmark added" toast):
/**
* Add a bookmark to the database.
*
* #param context
* Context of the calling Activity. This is used to make Toast confirming that the bookmark has been added. If the caller provides null, the Toast will not be shown.
* #param cr
* The ContentResolver being used to add the bookmark to the db.
* #param url
* URL of the website to be bookmarked.
* #param name
* Provided name for the bookmark.
* #param thumbnail
* A thumbnail for the bookmark.
* #param retainIcon
* Whether to retain the page's icon in the icon database. This will usually be <code>true</code> except when bookmarks are added by a settings restore agent.
*/
static void addBookmark(Context context, ContentResolver cr, String url, String name, Bitmap thumbnail, boolean retainIcon) {
final String WHERE_CLAUSE = "url = ? OR url = ? OR url = ? OR url = ?";
final String WHERE_CLAUSE_SECURE = "url = ? OR url = ?";
String[] SELECTION_ARGS;
// Want to append to the beginning of the list
long creationTime = new Date().getTime();
// First we check to see if the user has already visited this
// site. They may have bookmarked it in a different way from
// how it's stored in the database, so allow different combos
// to map to the same url.
boolean secure = false;
String compareString = url;
if (compareString.startsWith("http://")) {
compareString = compareString.substring(7);
} else if (compareString.startsWith("https://")) {
compareString = compareString.substring(8);
secure = true;
}
if (compareString.startsWith("www.")) {
compareString = compareString.substring(4);
}
if (secure) {
SELECTION_ARGS = new String[2];
SELECTION_ARGS[0] = "https://" + compareString;
SELECTION_ARGS[1] = "https://www." + compareString;
} else {
SELECTION_ARGS = new String[4];
SELECTION_ARGS[0] = compareString;
SELECTION_ARGS[1] = "www." + compareString;
SELECTION_ARGS[2] = "http://" + compareString;
SELECTION_ARGS[3] = "http://" + SELECTION_ARGS[1];
}
Cursor cursor = cr.query(Browser.BOOKMARKS_URI, Browser.HISTORY_PROJECTION, secure ? WHERE_CLAUSE_SECURE : WHERE_CLAUSE, SELECTION_ARGS, null);
ContentValues map = new ContentValues();
if (cursor.moveToFirst() && cursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX) == 0) {
// This means we have been to this site but not bookmarked
// it, so convert the history item to a bookmark
map.put(Browser.BookmarkColumns.CREATED, creationTime);
map.put(Browser.BookmarkColumns.TITLE, name);
map.put(Browser.BookmarkColumns.BOOKMARK, 1);
// map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
cr.update(Browser.BOOKMARKS_URI, map, "_id = " + cursor.getInt(0), null);
} else {
int count = cursor.getCount();
boolean matchedTitle = false;
for (int i = 0; i < count; i++) {
// One or more bookmarks already exist for this site.
// Check the names of each
cursor.moveToPosition(i);
if (cursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX).equals(name)) {
// The old bookmark has the same name.
// Update its creation time.
map.put(Browser.BookmarkColumns.CREATED, creationTime);
cr.update(Browser.BOOKMARKS_URI, map, "_id = " + cursor.getInt(0), null);
matchedTitle = true;
break;
}
}
if (!matchedTitle) {
// Adding a bookmark for a site the user has visited,
// or a new bookmark (with a different name) for a site
// the user has visited
map.put(Browser.BookmarkColumns.TITLE, name);
map.put(Browser.BookmarkColumns.URL, url);
map.put(Browser.BookmarkColumns.CREATED, creationTime);
map.put(Browser.BookmarkColumns.BOOKMARK, 1);
map.put(Browser.BookmarkColumns.DATE, 0);
// map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
int visits = 0;
if (count > 0) {
// The user has already bookmarked, and possibly
// visited this site. However, they are creating
// a new bookmark with the same url but a different
// name. The new bookmark should have the same
// number of visits as the already created bookmark.
visits = cursor.getInt(Browser.HISTORY_PROJECTION_VISITS_INDEX);
}
// Bookmark starts with 3 extra visits so that it will
// bubble up in the most visited and goto search box
map.put(Browser.BookmarkColumns.VISITS, visits + 3);
cr.insert(Browser.BOOKMARKS_URI, map);
}
}
if (retainIcon) {
WebIconDatabase.getInstance().retainIconForPageUrl(url);
}
cursor.close();
}