How to close the card by itself after executed a HTTP request? - google-glass

I have an app with contextual commands. After triggered a contextual command, it will make a HTTP request with a link and post the result on the card, something like, "Completed!". I want this card to be closed by itself after one second so that the user need not to tap to close it. Once the result card is closed, it will go back to contextual command lists with "Ok, glass" at footer and ready for next command.
May i know how to do that?
private class HTTPRequest extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
try {
if (mWhat.equalsIgnoreCase("GET")) {
// get json via YouTube API
URL url = new URL("http://example.com");
mUrlConnection = (HttpURLConnection)
url.openConnection();
InputStream in = new BufferedInputStream(
mUrlConnection.getInputStream());
int ch;
StringBuffer b = new StringBuffer();
while ((ch = in.read()) != -1) {
b.append((char) ch);
}
mResult = new String(b);
}
} catch (Exception e) {}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
mTvInfo.setText(mResult);
}

You can use an Android Dialog for this:
Use CardBuilder to create the "Completed" card using the MENU layout.
Create a new instance of Dialog and set its content view to be the view returned by CardBuilder.getView.
Show the dialog.
Use Handler.postDelayed (or some similar mechanism) to automatically dismiss the dialog after the desired amount of time has passed.

Related

UWP - Platform::DisconnectedException while navigating between pages

I've got the following setup: A MainPage xaml-view and a SettingPage xaml-view. In the SettingPage xaml-view I activated the back button which is in the window title bar and I added a BackRequestedEventArgs. (Furthermore I have a DX12 xaml page but it is not involved to the navigation yet, so it will never get initialized.)
So my problem is: if I click on a flyoutitem called settings which is located in the MainPage, I'll get navigated to the SettingPage. The backbutton appears in the titlebar and if I click it, I get back to the MainPage. Now I do it once again: clicking on settings, navigating to SettingPage. Now if I click on the backbutton OR close the window the app crashes and shows me the following exception:
Platform::DisconnectedException ^ at 0x046BED80. HRESULT:0x80010108
My Question: How do I fix it?
Here is my Code for it:
MainPage Navigation:
void MainPage::MenuFlyoutItemSettings_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(SettingsPage::typeid));
}
SettingsPage:
// in Constructor
Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->AppViewBackButtonVisibility = Windows::UI::Core::AppViewBackButtonVisibility::Visible;
Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
BackRequested += ref new Windows::Foundation::EventHandler<
Windows::UI::Core::BackRequestedEventArgs^>(
this, &SettingsPage::App_BackRequested);
void SettingsPage::App_BackRequested(
Platform::Object^ sender,
Windows::UI::Core::BackRequestedEventArgs^ e)
{
Windows::UI::Xaml::Controls::Frame^ rootFrame = dynamic_cast<Windows::UI::Xaml::Controls::Frame^>(Window::Current->Content);
if (rootFrame == nullptr)
return;
// Navigate back if possible, and if the event has not
// already been handled.
if (rootFrame->CanGoBack && e->Handled == false)
{
e->Handled = true;
rootFrame->GoBack();
}
}
Furthermore both methods have onSuspending and onResuming handlers added by me manually, but they are both empty:
//in constructor
Application::Current->Suspending += ref new SuspendingEventHandler(this, &SettingsPage::OnSuspending);
Application::Current->Resuming += ref new EventHandler<Object^>(this, &SettingsPage::OnResuming);
void SettingsPage::OnSuspending(Object^ sender, SuspendingEventArgs^ e) {
}
void SettingsPage::OnResuming(Object^ sender, Object^ e) {
}
NOTE: If I delete the whole backbutton-code, the app never crashes with this exception, so I think it is an error in this code.
EDIT 2017-09-04:
After working on Sunteen Wu - MSFT's Answer from below I realised that even If I delete all the backbutton-code I will get this exception as soon as I enter the SettingsPage the first time and close the app. So here is my current scenario where I am getting the described exception:
The only code I've got now for navigation:
MainPage (in a custom settingsbutton):
this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(SettingsPage::typeid));
SettingsPage (in a custom backbutton):
this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(MainPage::typeid));
So after the first time I navigate to the settingspage by pressing the settingsbutton I get the described exception only if I shutdown the app (same if clicking on red x or stopping debugger). The navigation works fine though, I can swap between the pages as long as I want and I won't get the exception while running the app.
FINAL ANSWER 2017-09-06:
Combining Sunteen Wu - MSFT's Answer with deleting the above mentioned
Application::Current->Suspending += ref new SuspendingEventHandler(this, &SettingsPage::OnSuspending);
Application::Current->Resuming += ref new EventHandler<Object^>(this, &SettingsPage::OnResuming);
handlers is the solution for me. Now there is no Disconnectedexception and the Back-Button-Logic is also working!
Platform::DisconnectedException ^ at 0x046BED80. HRESULT:0x80010108
Actually you are meeting the cycles issue. For what it the cycles issue and how to resolve please reference Weak references and breaking cycles (C++/CX). You met the cycles issue when you subscribe the BackRequested event handle. With the WeakReference you will find the issue:
WeakReference wr(this);
Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
BackRequested += ref new Windows::Foundation::EventHandler<
Windows::UI::Core::BackRequestedEventArgs^>([wr](
Object^ sender, Windows::UI::Core::BackRequestedEventArgs^ e)
{
SettingsPage^ c = wr.Resolve<SettingsPage>();
if (c != nullptr)
{
Windows::UI::Xaml::Controls::Frame^ rootFrame = dynamic_cast<Windows::UI::Xaml::Controls::Frame^>(Window::Current->Content);
if (rootFrame == nullptr)
return;
if (rootFrame->CanGoBack && e->Handled == false)
{
e->Handled = true;
rootFrame->GoBack();
}
}
else
{
throw ref new DisconnectedException();
}
});
From the article, when an event handler throws DisconnectedException, it causes the event to remove the handler from the subscriber list. So that to resolve it, you can remove the event handle from subscriber list after back requested. The following code snippet showed how to remove.
Windows::Foundation::EventRegistrationToken cookie;
SettingsPage::SettingsPage()
{
InitializeComponent();
...
cookie = Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
BackRequested += ref new Windows::Foundation::EventHandler<
Windows::UI::Core::BackRequestedEventArgs^>(
this, &SettingsPage::App_BackRequested);
}
void SettingsPage::App_BackRequested(
Platform::Object^ sender,
Windows::UI::Core::BackRequestedEventArgs^ e)
{
...
Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
BackRequested -= cookie;
}
Additionally, I recommend you subscribe this event inside App.xaml.cpp to avoid this issue. You can subscribe it inside OnLaunched like follows:
void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e)
{
auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content);
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
...
}
else
{
...
}
Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->
BackRequested += ref new Windows::Foundation::EventHandler<
Windows::UI::Core::BackRequestedEventArgs^>(
this, &App::App_BackRequested);
}
void App::App_BackRequested(
Platform::Object^ sender,
Windows::UI::Core::BackRequestedEventArgs^ e)
{
...
}
More details you can reference BackButton official sample.

wicket I'm using three panels, but only one is displayed at a time, when the third panel is added to the code the second never appears

I have a Modal class, when this modal is opened, it shows a panel asking the user if the user wants to proceed with the operation. If the user selects Yes the request is sent to the DB, which takes some time, during this time the first panel should be replaced by the second (which displays a spinner). This indeed happens if we do not use the third panel. Although I want to replace the second panel by the third panel in order to inform the user if the operation was successful or not (which depends of the message object,if it is null or have an error message).
So when I use addNewPanel(panel3, target) I never see panel2. I put a thread.sleep(5000) instruction after addNewPanel(panel2, target) and even so, this panel didn't appeared, I only get the initial and panel3 in the end.
If I do not use panel3 I see panel2.
Does anyone have an idea why is this happening?
Below I have the code of the Modal class
public class DetailsModal2 extends Modal<IModel<UserDomain>>{
#SpringBean
private IService service;
private BootstrapAjaxLink<String> noButton;
private ResponseMessage message;
private ProcessingPanel panel2;
private AlertPanel panel3;
private Panel replacedPanel;
public DetailsModal2(String id, IModel<UserDomain> model){
super(id);
replacedPanel = new AreYouSure("replacedPanel");
replacedPanel.setOutputMarkupId(true);
add(replacedPanel);
panel2 = new ProcessingPanel("replacedPanel");
panel3 = new AlertPanel("replacedPanel");
addButton(new BootstrapAjaxLink<String>("button", null, Buttons.Type.Warning, new ResourceModel("details")){
private static final long serialVersionUID = 1L;
#Override
public void onClick(AjaxRequestTarget target) {
// TODO Auto-generated method stub
//I was expecting to see this panel
addNewPanel(panel2,target);
// this puts this button invisible
this.setVisible(false);
target.add(this);
//this changes the label of the No button to Close
noButton.setLabel(Model.of("Close"));
target.add(noButton);
if(!service.retrieveData())
{
message = service.addUser("X");
if(message == null){
panel3.updateClassAndText(true);
addNewPanel(panel3,target);
}
else {
panel3.updateClassAndText(false);
addNewPanel(panel3,target);
System.out.println(""+ message.getError());
}
}//close if
else if(service.retrieveData())
{
message = service.removeUser("X");
if(message == null){
panel3.updateClassAndText(true);
addNewPanel(panel3,target);
}
else{
panel3.updateClassAndText(false);
addNewPanel(panel3,target);
System.out.println(""+ message.getError());
}
}
else{
System.out.println("It was not possible to access the db");
}
}
}
});
noButton = new BootstrapAjaxLink<String>("button", null, Buttons.Type.Primary){
private static final long serialVersionUID = 1L;
#Override
public void onClick(AjaxRequestTarget target) {
close(target);
}
}.setLabel(Model.of("No"));
addButton(noButton);
}
public void addNewPanel(Panel addpanel, AjaxRequestTarget target ){
Panel newPanel = null;
newPanel = addpanel;
newPanel.setOutputMarkupId(true);
replacedPanel.replaceWith(newPanel);
target.add(newPanel);
}
}//close class
HTML
<wicket:extend>
<div><span wicket:id="replacedPanel"> </span></div>
</wicket:extend>
Wicket atmosphere is deprecated from wicket 8 and will not be supported anymore, so do not use it ..

Repaining listfield on editfield change Input

I am using Google place API in my application for searching location. When user input text in edit field then the API called and resulted output will shown in a list.
I implemented it successfully but the problem is that each time edit field text changes, the list is not repainting and output is added to the end of the list. I want every time the text changes in the edit text field, the list must remove its previous content that are invalid.
This can be seen in pictures:
For Implementing this, I have written this code:
public final class MyScreen extends MainScreen {
/**
* Creates a new MyScreen object
*/
private Vector _listElements;
ListField list;
JSONObject[] jsonobject;
EditField editfield;
String url = "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=";
String[] locationName;
VerticalFieldManager verticalFieldManager = new VerticalFieldManager();
public MyScreen() {
ButtonField search = new ButtonField("Search");
_listElements = new Vector();
list = new ListField();
ListCallback _callback = new ListCallback(this);
// Set the displayed title of the screen
setTitle("Search Edit Field");
editfield = new EditField();
editfield.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
list.invalidate();
createField();
}
});
}
});
list.setCallback(_callback);
add(editfield);
add(new SeparatorField());
verticalFieldManager.add(list);
add(verticalFieldManager);
}
protected void createField() {
ShowList();
reloadList();
}
private void reloadList() {
list.setSize(_listElements.size());
}
class ListCallback implements ListFieldCallback {
MyScreen listDemoScreen;
public ListCallback(MyScreen listDemoScreen) {
this.listDemoScreen = listDemoScreen;
}
public void drawListRow(ListField list, Graphics g, int index, int y,
int w) {
String text = (String) _listElements.elementAt(index);
list.setRowHeight(getFont().getHeight());
g.drawText(text, 0, y, 0, -1);
}
public Object get(ListField list, int index) {
return _listElements.elementAt(index);
}
public int indexOfList(ListField list, String prefix, int string) {
return _listElements.indexOf(prefix, string);
}
public int getPreferredWidth(ListField list) {
return Display.getWidth();
}
}
protected void ShowList() {
HttpConnection httpConn;
InputStream in;
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
String response;
String fieldText = editfield.getText();
connDesc = connFact.getConnection(url + fieldText
+ "%#&sensor=true&key=xxxxxxxxxxxxx"
+ ConnectionType.getConnectionType());
if (connDesc != null) {
httpConn = (HttpConnection) connDesc.getConnection();
try {
int responseCode = httpConn.getResponseCode();
if (responseCode == HttpConnection.HTTP_OK) {
in = httpConn.openInputStream();
StringBuffer buf = new StringBuffer();
int read = -1;
while ((read = in.read()) != -1)
buf.append((char) read);
response = buf.toString();
try {
JSONObject object = new JSONObject(response);
JSONArray ar = object.getJSONArray("predictions");
jsonobject = new JSONObject[ar.length()];
locationName = new String[ar.length()];
list.invalidate();
for (int i = 0; i < ar.length(); i++) {
jsonobject[i] = ar.getJSONObject(i);
_listElements.addElement(jsonobject[i]
.getString("description"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
Dialog.alert("Connection not succeded");
}
}
protected boolean onSavePrompt() {
return true;
}
}
Update and Solution:
only modify this and this rest is working fine. As Peter Suggests, we can also put a Thread.sleep(time); in order to get the UI not blocked:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_listElements.removeAllElements();
createField();
}
});
I think your problem is simply that you do not clear the _listElements Vector when you request more data. So _listElements just gets bigger.
However there is a bigger problem here and that is that your code appears to be running networking operations on the Event Thread. What your should do in your changeListener. is start a Thread that requests the data, then repopulate the ListField when this tread gets data.
As a result of this change, the UI will not be blocked, and the List updates will become asynchronous, so your user could in fact enter another character into the EditField before the first Thread response comes back. To prevent this looking silly, you could delay the Thread processing for a fraction of second to see if another character is entered, and/or you could make sure that the EditField content was still the same as the requested characters before you repopulate it.
I personally prefer this asynchronous approach, but if it bothers you, you could put a 'please wait - loading' type screen to block the user until the response comes back.
Update
Remember that if you start a background Thread, you need to get back onto the Event Thread to do Ui Processing. Typically this is done simply by including your UI code within the run method of a Runnable that is invoked later, for example:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// Ui Code in here
}
});
You should only put Ui Updating code in the runnable. Networking processing, or any other blocking action, should NOT be included.

Launch a fragment in my Android application from the notification bar

How do I start a fragment in my Android application from a notification in the notification bar?
I've tried to implement this answer of creating my own action and then setting the action to the intent, but I'm unsure how to use it and what is required additionally - like adding something to the Manifest.
I've got a notification class that receives a context, a message and then an action. I then want to filter on that action to determine which fragment to launch, but I don't know how to launch a fragment as opposed to launching an activity.
Here is my Notifications.java class (incomplete):
public class Notifications {
private Context mContext;
public Notifications(Context context) {
this.mContext = context;
}
public static void notify(Context context, String message, String action) {
//Action you invent should include the application package as a prefix — for example: "com.example.project.SHOW_COLOR".
action = "my.package.name.here.frag."+action;
//Construct a user message.
String appName = context.getResources().getString(R.string.app_name);
// Use the Notification manager to send notification
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Create a notification using android stat_notify_chat icon.
Notification notification = new Notification(R.drawable.ic_stat_notification, message, 0);
//Sound, lights, vibration.
//REMEMBER PERMISSIONS.
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.defaults |= Notification.DEFAULT_LIGHTS;
// Create a pending intent to open the application when the notification is clicked.
//Restart the app.
Intent launchIntent = null;
//Get the action and based on what the action is, launch the application displaying the appropriate fragment.
if (action.equalsIgnoreCase("friend")){
//New friend notification
//Launch application displaying the list of friends
}
if (action.equalsIgnoreCase("article")){
//New article has been posted
//Launch application displaying the news feed fragment
}
if (action.equalsIgnoreCase("points")){
//Points scored notification
//Launch application displaying the user's profile
}
if (action.equalsIgnoreCase("redeemable")){
//New redeemable is offered
//Launch application displaying the list of redeemables
}
if (!action.equalsIgnoreCase("friend")
&& !action.equalsIgnoreCase("article")
&& !action.equalsIgnoreCase("points")
&& !action.equalsIgnoreCase("redeemable")){
//Not specific, so launch the application from scratch displaying the activity feed
launchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
}
if(action != null && launchIntent != null){
launchIntent.setAction(action);
}
// Set the notification and register the pending intent to it
notification.setLatestEventInfo(context, appName, message, pendingIntent);
// Trigger the notification
notificationManager.notify(0, notification);
}
}
So this was actually pretty easy. Hopefully I can help someone else see this too.
I send an action to this notify function. The I add that action to my intent to launch an activity. In my case I open the launching activity, because all the fragments are loaded from within that activity based on what the user does. So I set the action using setAction and the I use that action in the activity as below.
My Notifications.java class changed to this:
public static void notify(Context context, String message, String action) {
action = action.toUpperCase();
// Create a pending intent to open the the application when the notification is clicked.
//Restart the app.
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
if(action != null && launchIntent != null){
launchIntent.setAction(action);
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.when = System.currentTimeMillis();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Set the notification and register the pending intent to it
notification.setLatestEventInfo(context, appName, message, pendingIntent);
// Trigger the notification
notificationManager.notify(0, notification);
}
And then in my activity from where I load the fragments, I get the action and filter it:
Intent intent = getIntent();
try{
String action = intent.getAction().toUpperCase();
if(action != null){
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_friend))){
goFrag(getResources().getInteger(R.integer.FRAG_A_INT));
}
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_article))){
goFrag(getResources().getInteger(R.integer.FRAG_B_INT));
}
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_points))){
goFrag(getResources().getInteger(R.integer.FRAG_C_INT));
}
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_redeemable))){
goFrag(getResources().getInteger(R.integer.FRAG_D_INT));
}
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_dance))){
goFrag(getResources().getInteger(R.integer.FRAG_E_INT));
}
}else{
Log.d(TAG, "Intent was null");
}
}catch(Exception e){
Log.e(TAG, "Problem consuming action from intent", e);
}
In my goFrag function I replace the fragment if the required fragment is still in memory (meaning the user was there earlier and it hasn't been destroyed yet), or I create a new fragment required.

Determine if MS Word finished saving the document

I have a Silverlight 5.0 application and prvoide MS Word Automation functionality where the user can edit/add new document. I have gone through to MSDN pages but couldn't find any event that MS Word triggers after saving the document. The only event that talks about saving is the "DocumentBeforeSave" event that dosen't helps. I need to know when the MS Word finishes saving the document so that is it ready to save to server.
Can someone help me with this?
Any idea is very much approciated.
using MSWord = Microsoft.Office.Interop.Word;
namespace ConsoleApplication4
{
class Program
{
static void Main()
{
var app = new MSWord.Application();
var doc = app.Documents.Open(#"..\..\myDoc.docx");
app.DocumentBeforeSave += app_DocumentBeforeSave;
}
static void app_DocumentBeforeSave(MSWord.Document Doc, ref bool SaveAsUI, ref bool Cancel)
{
app.DocumentBeforeSave -= app_DocumentBeforeSave;
Cancel = true;
Doc.Save();
if(Doc.Saved){
//Now you know the document has saved
}
app.DocumentBeforeSave += app_DocumentBeforeSave;
}
}
}
The Save method doesn't run on a seperate thread, so it only returns once the Save is complete.
The DocumentBeforeSave event takes in a boolean call Cancel this is passed with the ref parameter, and setting it to true cancels the save that is about to take place.
You could set this to true, and then call Save yourself, this way you will know when the save has completed, as it runs on the same thread, something like this:
using MSWord = Microsoft.Office.Interop.Word;
namespace ConsoleApplication41
{
class Program
{
static void Main()
{
var app = new MSWord.Application();
var doc = app.Documents.Open(#"..\..\myDoc.docx");
app.DocumentBeforeSave += app_DocumentBeforeSave;
}
static void app_DocumentBeforeSave(MSWord.Document Doc, ref bool SaveAsUI, ref bool Cancel)
{
Cancel = true;
Doc.Save();
//Now you know the document has saved
}
}
}