Java tutorial
/* * Copyright (C) 2013 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.android.talkback.menurules; import android.annotation.TargetApi; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.text.TextUtils; import android.util.Pair; import android.view.Menu; import android.view.MenuItem; import android.widget.ImageView; import com.android.talkback.FeedbackItem; import com.android.talkback.R; import com.android.talkback.SpeechController; import com.android.talkback.labeling.LabelDialogManager; import com.android.utils.Role; import com.google.android.marvin.talkback.TalkBackService; import com.android.talkback.contextmenu.ContextMenuItem; import com.android.talkback.contextmenu.ContextMenuItemBuilder; import com.android.utils.AccessibilityNodeInfoUtils; import com.android.utils.labeling.CustomLabelManager; import com.android.utils.labeling.Label; import java.util.LinkedList; import java.util.List; /** * Processes {@link ImageView} nodes without text. */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) class RuleUnlabeledImage implements NodeMenuRule { @Override public boolean accept(TalkBackService service, AccessibilityNodeInfoCompat node) { final @Role.RoleName int role = Role.getRole(node); // TODO: node.hasImage(); final boolean isImage = (role == Role.ROLE_IMAGE || role == Role.ROLE_IMAGE_BUTTON); final boolean hasDescription = !TextUtils.isEmpty(AccessibilityNodeInfoUtils.getNodeText(node)); return (isImage && !hasDescription); } @Override public List<ContextMenuItem> getMenuItemsForNode(TalkBackService service, ContextMenuItemBuilder menuItemBuilder, AccessibilityNodeInfoCompat node) { List<ContextMenuItem> items = new LinkedList<>(); CustomLabelManager labelManager = service.getLabelManager(); if (labelManager == null) { return items; } AccessibilityNodeInfoCompat nodeCopy = AccessibilityNodeInfoCompat.obtain(node); Label viewLabel = labelManager.getLabelForViewIdFromCache(nodeCopy.getViewIdResourceName()); if (viewLabel == null) { final ContextMenuItem addLabel = menuItemBuilder.createMenuItem(service, Menu.NONE, R.id.labeling_breakout_add_label, Menu.NONE, service.getString(R.string.label_dialog_title_add)); items.add(addLabel); } else { ContextMenuItem editLabel = menuItemBuilder.createMenuItem(service, Menu.NONE, R.id.labeling_breakout_edit_label, Menu.NONE, service.getString(R.string.label_dialog_title_edit)); ContextMenuItem removeLabel = menuItemBuilder.createMenuItem(service, Menu.NONE, R.id.labeling_breakout_remove_label, Menu.NONE, service.getString(R.string.label_dialog_title_remove)); items.add(editLabel); items.add(removeLabel); } for (ContextMenuItem item : items) { item.setOnMenuItemClickListener(new UnlabeledImageMenuItemClickListener(service, nodeCopy, viewLabel)); // Prevent re-speaking the node description right before showing the dialog. item.setSkipRefocusEvents(true); } return items; } @Override public CharSequence getUserFriendlyMenuName(Context context) { return context.getString(R.string.title_labeling_controls); } @Override public boolean canCollapseMenu() { return true; } private static class UnlabeledImageMenuItemClickListener implements MenuItem.OnMenuItemClickListener { private final TalkBackService mContext; private final AccessibilityNodeInfoCompat mNode; private final Label mExistingLabel; public UnlabeledImageMenuItemClickListener(TalkBackService service, AccessibilityNodeInfoCompat node, Label label) { mContext = service; mNode = node; mExistingLabel = label; } @Override public boolean onMenuItemClick(MenuItem item) { if (item == null) { mNode.recycle(); return true; } mContext.saveFocusedNode(); final int itemId = item.getItemId(); if (itemId == R.id.labeling_breakout_add_label) { if (!canAddLabel()) { mContext.getSpeechController().speak(mContext.getString(R.string.cannot_add_label), SpeechController.QUEUE_MODE_FLUSH_ALL, FeedbackItem.FLAG_NO_HISTORY, null); return false; } return LabelDialogManager.addLabel(mContext, mNode, true /* overlay */); } else if (itemId == R.id.labeling_breakout_edit_label) { return LabelDialogManager.editLabel(mContext, mExistingLabel, true /* overlay */); } else if (itemId == R.id.labeling_breakout_remove_label) { return LabelDialogManager.removeLabel(mContext, mExistingLabel, true /* overlay */); } mNode.recycle(); return true; } private boolean canAddLabel() { final Pair<String, String> parsedId = CustomLabelManager .splitResourceName(mNode.getViewIdResourceName()); final boolean hasParseableId = (parsedId != null); // TODO: There are a number of views that have a // different resource namespace than their parent application. It's // likely we'll need to refine the database structure to accommodate // these while also allowing the user to modify them through TalkBack // settings. For now, we'll simply not allow labeling of such views. boolean isFromKnownApp = false; if (hasParseableId) { try { mContext.getPackageManager().getPackageInfo(parsedId.first, 0); isFromKnownApp = true; } catch (NameNotFoundException e) { // Do nothing. } } return (hasParseableId && isFromKnownApp); } } }