1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * Copyright (C) 2016 Mopria Alliance, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.bips.ui; 19 20 import android.annotation.SuppressLint; 21 import android.app.Activity; 22 import android.app.AlertDialog; 23 import android.content.Context; 24 import android.net.Uri; 25 import android.os.Bundle; 26 import android.text.Editable; 27 import android.text.TextWatcher; 28 import android.util.Log; 29 import android.view.KeyEvent; 30 import android.view.View; 31 import android.view.Window; 32 import android.view.WindowManager; 33 import android.view.inputmethod.EditorInfo; 34 import android.view.inputmethod.InputMethodManager; 35 import android.widget.Button; 36 import android.widget.ProgressBar; 37 import android.widget.TextView; 38 39 import com.android.bips.R; 40 import com.android.bips.discovery.DiscoveredPrinter; 41 import com.android.bips.discovery.ManualDiscovery; 42 43 import java.util.regex.Matcher; 44 import java.util.regex.Pattern; 45 46 /** 47 * Allows the user to enter printer address manually 48 */ 49 class AddManualPrinterDialog extends AlertDialog implements TextWatcher, 50 TextView.OnEditorActionListener, View.OnKeyListener, ManualDiscovery.PrinterAddCallback { 51 private static final String TAG = AddManualPrinterDialog.class.getSimpleName(); 52 private static final boolean DEBUG = false; 53 54 /** 55 * A regex matching any printer URI with optional protocol, port and path. 56 */ 57 private static final String URI_REGEX = 58 "(ipp[s]?://)?[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*(:[0-9]+)?(/.*)?"; 59 private static final String FULL_URI_REGEX = "^" + URI_REGEX + "$"; 60 private static final Pattern FULL_URI_PATTERN = Pattern.compile(FULL_URI_REGEX); 61 62 private final ManualDiscovery mDiscovery; 63 private final Activity mActivity; 64 private TextView mHostnameView; 65 private Button mAddButton; 66 private ProgressBar mProgressBar; 67 AddManualPrinterDialog(Activity activity, ManualDiscovery discovery)68 AddManualPrinterDialog(Activity activity, ManualDiscovery discovery) { 69 super(activity); 70 mDiscovery = discovery; 71 mActivity = activity; 72 } 73 74 @SuppressLint("InflateParams") 75 @Override onCreate(Bundle savedInstanceState)76 protected void onCreate(Bundle savedInstanceState) { 77 if (DEBUG) Log.d(TAG, "onCreate"); 78 View view = getLayoutInflater().inflate(R.layout.manual_printer_add, null); 79 setView(view); 80 setTitle(R.string.add_printer_by_ip); 81 setButton(AlertDialog.BUTTON_NEGATIVE, getContext().getString(android.R.string.cancel), 82 (OnClickListener) null); 83 setButton(AlertDialog.BUTTON_POSITIVE, getContext().getString(R.string.add), 84 (OnClickListener) null); 85 86 super.onCreate(savedInstanceState); 87 mAddButton = getButton(AlertDialog.BUTTON_POSITIVE); 88 mHostnameView = findViewById(R.id.hostname); 89 mProgressBar = findViewById(R.id.progress); 90 91 mAddButton.setOnClickListener(view1 -> addPrinter()); 92 93 // Update add button as contents change 94 mHostnameView.addTextChangedListener(this); 95 mHostnameView.setOnEditorActionListener(this); 96 mHostnameView.setOnKeyListener(this); 97 98 // Force open keyboard if appropriate 99 openKeyboard(mHostnameView); 100 101 updateButtonState(); 102 } 103 104 @Override onStop()105 protected void onStop() { 106 if (DEBUG) Log.d(TAG, "onStop()"); 107 super.onStop(); 108 mDiscovery.cancelAddManualPrinter(this); 109 } 110 openKeyboard(TextView view)111 private void openKeyboard(TextView view) { 112 Window window = getWindow(); 113 if (window != null) { 114 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); 115 } 116 117 view.requestFocus(); 118 InputMethodManager imm = (InputMethodManager) getContext() 119 .getSystemService(Context.INPUT_METHOD_SERVICE); 120 imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); 121 } 122 updateButtonState()123 private void updateButtonState() { 124 String hostname = mHostnameView.getText().toString(); 125 Matcher uriMatcher = FULL_URI_PATTERN.matcher(hostname); 126 mAddButton.setEnabled(uriMatcher.matches()); 127 } 128 129 /** Attempt to add the printer based on current data */ addPrinter()130 private void addPrinter() { 131 // Disable other actions while we are checking 132 mAddButton.setEnabled(false); 133 mHostnameView.setEnabled(false); 134 mProgressBar.setVisibility(View.VISIBLE); 135 136 // Begin an attempt to add the printer 137 String uriString = mHostnameView.getText().toString(); 138 Uri printerUri; 139 if (uriString.contains("://")) { 140 printerUri = Uri.parse(uriString); 141 } else { 142 // create a schemeless URI 143 printerUri = Uri.parse("://" + uriString); 144 } 145 mDiscovery.addManualPrinter(printerUri, this); 146 } 147 148 @Override onFound(DiscoveredPrinter printer, boolean supported)149 public void onFound(DiscoveredPrinter printer, boolean supported) { 150 if (supported) { 151 // Success case 152 dismiss(); 153 mActivity.finish(); 154 } else { 155 error(getContext().getString(R.string.printer_not_supported)); 156 } 157 } 158 159 @Override onNotFound()160 public void onNotFound() { 161 error(getContext().getString(R.string.no_printer_found)); 162 } 163 164 /** Inform user of error and allow them to correct it */ error(String message)165 private void error(String message) { 166 mProgressBar.setVisibility(View.GONE); 167 mHostnameView.setError(message); 168 mHostnameView.setEnabled(true); 169 openKeyboard(mHostnameView); 170 } 171 172 @Override beforeTextChanged(CharSequence charSequence, int start, int count, int after)173 public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { 174 } 175 176 @Override onTextChanged(CharSequence charSequence, int start, int before, int count)177 public void onTextChanged(CharSequence charSequence, int start, int before, int count) { 178 } 179 180 @Override afterTextChanged(Editable editable)181 public void afterTextChanged(Editable editable) { 182 updateButtonState(); 183 } 184 185 @Override onEditorAction(TextView textView, int id, KeyEvent keyEvent)186 public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) { 187 if (id == EditorInfo.IME_ACTION_DONE && mAddButton.isEnabled()) { 188 addPrinter(); 189 return true; 190 } 191 return false; 192 } 193 194 @Override onKey(View view, int keyCode, KeyEvent keyEvent)195 public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { 196 if (keyCode == KeyEvent.KEYCODE_ENTER && mAddButton.isEnabled()) { 197 addPrinter(); 198 return true; 199 } 200 return false; 201 } 202 } 203