Skip to content

Commit

Permalink
(Sample) Add floating menus for phone, email and map addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
saket committed Oct 16, 2016
1 parent 70a04b3 commit 8acb489
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,28 +125,6 @@ public static BetterLinkMovementMethod linkifyHtml(Activity activity) {
return linkify(LINKIFY_NONE, activity);
}

private static void rAddLinks(int linkifyMask, ViewGroup viewGroup, BetterLinkMovementMethod movementMethod) {
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);

if (child instanceof ViewGroup) {
// Recursively find child TextViews.
rAddLinks(linkifyMask, ((ViewGroup) child), movementMethod);

} else if (child instanceof TextView) {
TextView textView = (TextView) child;
addLinks(linkifyMask, movementMethod, textView);
}
}
}

private static void addLinks(int linkifyMask, BetterLinkMovementMethod movementMethod, TextView textView) {
if (linkifyMask != LINKIFY_NONE) {
textView.setMovementMethod(movementMethod);
Linkify.addLinks(textView, linkifyMask);
}
}

/**
* Get a static instance of BetterLinkMovementMethod. Do note that registering a click listener on the returned
* instance is not supported because it will potentially be shared on multiple TextViews.
Expand Down Expand Up @@ -174,6 +152,29 @@ public BetterLinkMovementMethod setOnLinkClickListener(OnLinkClickListener onLin
return this;
}

// ======== PUBLIC APIs END ======== //

private static void rAddLinks(int linkifyMask, ViewGroup viewGroup, BetterLinkMovementMethod movementMethod) {
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);

if (child instanceof ViewGroup) {
// Recursively find child TextViews.
rAddLinks(linkifyMask, ((ViewGroup) child), movementMethod);

} else if (child instanceof TextView) {
TextView textView = (TextView) child;
addLinks(linkifyMask, movementMethod, textView);
}
}
}

private static void addLinks(int linkifyMask, BetterLinkMovementMethod movementMethod, TextView textView) {
if (linkifyMask != LINKIFY_NONE) {
textView.setMovementMethod(movementMethod);
Linkify.addLinks(textView, linkifyMask);
}
}

@Override
public boolean onTouchEvent(TextView view, Spannable text, MotionEvent event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,25 @@
/**
* Similar to Marshmallow's floating contextual menu.
*/
public class FloatingMenu extends PopupWindow implements View.OnClickListener {
public abstract class BaseFloatingMenu extends PopupWindow implements View.OnClickListener {

private final Context context;
private final View anchorView;
private final String phoneAddress;
private final String url;

public FloatingMenu(Context context, View anchorView, String phoneAddress) {
public BaseFloatingMenu(Context context, View anchorView, String url) {
super(context);
this.context = context;
this.anchorView = anchorView;
this.phoneAddress = phoneAddress;
}

public static void show(Context context, View anchorView, String phoneAddress) {
FloatingMenu floatingMenu = new FloatingMenu(context, anchorView, phoneAddress);
floatingMenu.show();
this.url = url;
}

/**
* Shows this menu popup anchored on the View set using {@link FloatingMenu#show(Context, View, String)}.
* Shows this menu popup.
*/
@SuppressLint("InflateParams")
public void show() {
final View menuLayout = LayoutInflater.from(context).inflate(R.layout.phone_number_floating_menu, null);
final View menuLayout = LayoutInflater.from(context).inflate(getMenuLayout(), null);
registerButtonClickListeners((ViewGroup) menuLayout);
setContentView(menuLayout);

Expand All @@ -62,6 +57,10 @@ public void show() {
showAtLocation(anchorView, Gravity.NO_GRAVITY, showPoint.x, showPoint.y);
}

protected abstract int getMenuLayout();

protected abstract void handleMenuClick(int menuItemId);

private void registerButtonClickListeners(ViewGroup menuLayout) {
// Find all buttons in the layout and register their click listeners.
for (int i = 0; i < menuLayout.getChildCount(); i++) {
Expand All @@ -87,51 +86,44 @@ private Point determineShowPoint(View menuLayout) {
return new Point(x, y);
}

public Context getContext() {
return context;
}

public String getURL() {
return url;
}

// ======== CLICK LISTENERS ======== //

@Override
public void onClick(View menuButton) {
switch (menuButton.getId()) {
case R.id.btn_call:
onCallAddressClick();
break;

case R.id.btn_compose_sms:
onComposeNewSmsClick();
break;

case R.id.btn_copy:
onCopyAddressClick();
break;

case R.id.btn_save:
onAddToContactsClick();
break;
}
handleMenuClick(menuButton.getId());
dismiss();
}


private void onCallAddressClick() {
Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(phoneAddress)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(url)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(dialIntent);
}

private void onComposeNewSmsClick() {
Intent smsIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:" + phoneAddress));
Intent smsIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:" + url));
context.startActivity(smsIntent);
}

private void onCopyAddressClick() {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
final ClipData clip = ClipData.newPlainText(context.getPackageName(), phoneAddress);
final ClipData clip = ClipData.newPlainText(context.getPackageName(), url);
clipboard.setPrimaryClip(clip);
Toast.makeText(context, "Copied to clipboard", Toast.LENGTH_SHORT).show();
}

private void onAddToContactsClick() {
final Intent addContactIntent = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT);
addContactIntent.putExtra("finishActivityOnSaveCompleted", true);
addContactIntent.setData(Uri.fromParts("tel", phoneAddress, null));
addContactIntent.setData(Uri.fromParts("tel", url, null));
addContactIntent.putExtra(ContactsContract.Intents.EXTRA_FORCE_CREATE, true);
context.startActivity(addContactIntent);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package me.saket.bettermovementmethod.sample;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.view.View;
import android.widget.Toast;

public class EmailFloatingMenu extends BaseFloatingMenu {

public static void show(Context context, View anchorView, String emailAddress) {
new EmailFloatingMenu(context, anchorView, emailAddress).show();
}

private EmailFloatingMenu(Context context, View anchorView, String phoneAddress) {
super(context, anchorView, phoneAddress);
}

@Override
protected int getMenuLayout() {
return R.layout.floating_menu_email;
}

@Override
protected void handleMenuClick(int menuItemId) {
switch (menuItemId) {
case R.id.btn_email:
onEmailAddressClick();
break;

case R.id.btn_copy:
onCopyAddressClick();
break;
}
}

private void onEmailAddressClick() {
Intent dialIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse(getURL()));
getContext().startActivity(dialIntent);
}

private void onCopyAddressClick() {
final ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
final ClipData clip = ClipData.newPlainText(getContext().getPackageName(), getURL());
clipboard.setPrimaryClip(clip);
Toast.makeText(getContext(), "Copied to clipboard", Toast.LENGTH_SHORT).show();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package me.saket.bettermovementmethod.sample;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.ContactsContract;
import android.view.View;
import android.widget.Toast;

public class FloatingMenuPhone extends BaseFloatingMenu {

public static void show(Context context, View anchorView, String phoneAddress) {
new FloatingMenuPhone(context, anchorView, phoneAddress).show();
}

private FloatingMenuPhone(Context context, View anchorView, String phoneAddress) {
super(context, anchorView, phoneAddress);
}

@Override
protected int getMenuLayout() {
return R.layout.floating_menu_phone_number;
}

@Override
protected void handleMenuClick(int menuItemId) {
switch (menuItemId) {
case R.id.btn_call:
onCallAddressClick();
break;

case R.id.btn_compose_sms:
onComposeNewSmsClick();
break;

case R.id.btn_copy:
onCopyAddressClick();
break;

case R.id.btn_save:
onAddToContactsClick();
break;
}
}

private void onCallAddressClick() {
Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(getURL())).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(dialIntent);
}

private void onComposeNewSmsClick() {
Intent smsIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:" + getURL()));
getContext().startActivity(smsIntent);
}

private void onCopyAddressClick() {
final ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
final ClipData clip = ClipData.newPlainText(getContext().getPackageName(), getURL());
clipboard.setPrimaryClip(clip);
Toast.makeText(getContext(), "Copied to clipboard", Toast.LENGTH_SHORT).show();
}

private void onAddToContactsClick() {
final Intent addContactIntent = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT);
addContactIntent.putExtra("finishActivityOnSaveCompleted", true);
addContactIntent.setData(Uri.fromParts("tel", getURL(), null));
addContactIntent.putExtra(ContactsContract.Intents.EXTRA_FORCE_CREATE, true);
getContext().startActivity(addContactIntent);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ protected void onCreate(Bundle savedInstanceState) {

BetterLinkMovementMethod.OnLinkClickListener urlClickListener = (view, url) -> {
if (isPhoneNumber(url)) {
FloatingMenu.show(this, view, url);
FloatingMenuPhone.show(this, view, url);

} else if (isEmailAddress(url)) {
EmailFloatingMenu.show(this, view, url);

} else if (isMapAddress(url)) {
MapFloatingMenu.show(this, view, url);

} else {
Toast.makeText(this, url, Toast.LENGTH_SHORT).show();
}
Expand All @@ -37,4 +44,12 @@ private boolean isPhoneNumber(String url) {
return url.endsWith(getString(R.string.bettermovementmethod_dummy_number));
}

private boolean isEmailAddress(String url) {
return url.contains("@");
}

private boolean isMapAddress(String url) {
return url.contains("goo.gl/maps");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package me.saket.bettermovementmethod.sample;

import android.content.Context;
import android.view.View;
import android.widget.Toast;

public class MapFloatingMenu extends BaseFloatingMenu {

public static void show(Context context, View anchorView, String mapAddress) {
new MapFloatingMenu(context, anchorView, mapAddress).show();
}

private MapFloatingMenu(Context context, View anchorView, String phoneAddress) {
super(context, anchorView, phoneAddress);
}

@Override
protected int getMenuLayout() {
return R.layout.floating_menu_map;
}

@Override
protected void handleMenuClick(int menuItemId) {
Toast.makeText(getContext(), "Just kidding", Toast.LENGTH_SHORT).show();
}

}
18 changes: 18 additions & 0 deletions sample/src/main/res/layout/floating_menu_email.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:ignore="HardcodedText">

<Button
android:id="@+id/btn_email"
style="@style/Button.FloatingMenu"
android:text="Email" />

<Button
android:id="@+id/btn_copy"
style="@style/Button.FloatingMenu"
android:text="Copy" />
</LinearLayout>
18 changes: 18 additions & 0 deletions sample/src/main/res/layout/floating_menu_map.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:ignore="HardcodedText">

<Button
android:id="@+id/btn_navigate"
style="@style/Button.FloatingMenu"
android:text="Navigate" />

<Button
android:id="@+id/btn_open"
style="@style/Button.FloatingMenu"
android:text="Open" />
</LinearLayout>

0 comments on commit 8acb489

Please sign in to comment.