mercredi 29 juin 2016

Android update app across app restarts using DownloadManager (avoid downloading multiple times)

Iam trying to update my app by downloading the apk using download manager. I have registered broadcast receiver to listen to DownloadManager.ACTION_DOWNLOAD_COMPLETE in MainActivity and open the apk in onReceive method. Following is the code:

public class MainActivity extends CordovaActivity {
private long downloadReference;
private DownloadManager downloadManager;
private IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    registerReceiver(downloadReceiver, intentFilter);

}

public void updateApp(String url) {
    //start downloading the file using the download manager
    downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    Uri Download_Uri = Uri.parse(url);
    DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
    request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
    request.setAllowedOverRoaming(false);
    request.setDestinationInExternalFilesDir(MainActivity.this, Environment.DIRECTORY_DOWNLOADS, "myapk.apk");
    downloadReference = downloadManager.enqueue(request);
}


@Override
public void onDestroy() {
    //unregister your receivers
    this.unregisterReceiver(downloadReceiver);
    super.onDestroy();
}

private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {

        //check if the broadcast message is for our Enqueued download
        long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
        if (downloadReference == referenceId) {

            //start the installation of the latest version
                    Intent installIntent = new Intent(Intent.ACTION_VIEW);
                installIntent.setDataAndType(downloadManager.getUriForDownloadedFile(downloadReference),
                        "application/vnd.android.package-archive");
                installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(installIntent);

        }

    }

};

}

updateApp(url) is called on click of a button in UI. Now after clicking the button, the download starts. Lets say the app is closed (receiver is unregistered) after initiating the download, I have problem with two scenarios when the app is started again.

  1. The previous download completes after my app is restarted -
    downloadReference is lost and when my receiver receives the broadcast, the referenceId wont be same as downloadReference, so installIntent is never started. So I have to click on Update button again and initiate the download. Is there a way to avoid this problem?

  2. The previous download completes before my app is restarted - There is no way of knowing that my previous download is complete in the newly started activity. Again I have to click the button and reinitiate the download. Is there a way to enable sticky broadcast for download manager?

Android Scroll Text View in Coordinatore layout + Recycler View

In my layout I have a Card View Layout containing HashTagView and then followed by recycler view. Using my existing code I am able to scroll through the recycler view. But I also want to be able to scroll the HashTagView itself.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:id="@+id/activity_main_id"
    tools:context="mymainactivity.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">


        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleMarginEnd="64dp"
            android:fitsSystemWindows="true">

            <android.support.v7.widget.CardView style="@style/Card">

                <LinearLayout style="@style/CardContainer"
                    android:isScrollContainer="true">


                        <com.greenfrvr.hashtagview.HashtagView
                            android:id="@+id/hashtags6"
                            style="@style/HashtagView"
                            app:rowGravity="center"
                            app:rowMode="stretch"
                            app:selectionMode="true"
                            app:tagBackground="@drawable/item_bg_1"
                            app:tagForeground="@drawable/flat_button_light"
                            app:tagPaddingBottom="@dimen/padding_vertical"
                            app:tagPaddingLeft="@dimen/padding_horizontal"
                            app:tagPaddingRight="@dimen/padding_horizontal"
                            app:tagPaddingTop="@dimen/padding_vertical"
                            app:tagTextColor="#E5E5E5" />



                </LinearLayout>
            </android.support.v7.widget.CardView>




            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_collapseMode="pin" />

        </android.support.design.widget.CollapsingToolbarLayout>


    </android.support.design.widget.AppBarLayout>




        <android.support.v7.widget.RecyclerView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />



</android.support.design.widget.CoordinatorLayout>

I want to acheive this kind of layout:-

Sample Layout of Samsung Galary App

How to change the default color scheme timepicker dialog fragment?

I am trying to change the default color the timepicker dialog fragment. and right now i have no idea as to what im supposed to be doing.

this what i have managed to set my theme to (withouth the actionBar):

enter image description here

but this is the dialog i get: enter image description here

this is my xml style file:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="AppTheme" parent="Theme.AppCompat.Light">
        <item name="colorPrimary">@color/color_accent</item>
        <item name="colorPrimaryDark">@color/color_secondary</item>
        <item name="colorAccent">@color/color_accent</item>
        <item name="android:statusBarColor">@color/color_primary</item>
    </style>
</resources>

My colors file:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="flat_text">#f14268</color>
    <color name="background_flatbtn">#fff</color>
    <color name="color_accent">#f14268</color>
    <color name="color_primary">#d83b5d</color>
    <color name="color_secondary">#d83b5d</color>
</resources>

mytimepicker fragment:

public class DialogHandler extends DialogFragment
        implements TimePickerDialog.OnTimeSetListener {
    Context context;

    public DialogHandler(Context context){
        this.context=context;

    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Use the current time as the default values for the picker
        final Calendar c = Calendar.getInstance();
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);
        TimePickerDialog dialog= new TimePickerDialog(new ContextThemeWrapper(getActivity(),R.style.AppTheme), this, hour, minute, DateFormat.is24HourFormat(getActivity()));
        // Create a new instance of TimePickerDialog and return it
        return dialog;
    }

    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        // Do something with the time chosen by the user
        Toast.makeText(context, "your time is selected",Toast.LENGTH_LONG).show();
    }
}

my dialogue call:

DialogHandler newFragment = new DialogHandler(getApplicationContext());
        newFragment.show(getSupportFragmentManager() , "time_Picker");

Please help me . Thanks in Advance :)

Android collapsable Toolbar menu icons disappearing

So I've implemented collapsable Toolbar inside my app and in Java class I override onCreateOptionsMenu and onOptionsItemSelected like this:

 @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_details, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_share:
                break;
            case R.id.action_addToFavorites:
                break;
        }
        return super.onOptionsItemSelected(item);
    }

And now when I open the activity I can see the menu icons and do stuff with them until the toolbar is colapsed. When user colapses the toolbar the icons disappears.

Second problem, with using the getSupportActionBar().setDisplayHomeAsUpEnabled(true); method i get back button of black color instead of white so now I'm using this method:

tToolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_action_navigation_arrow_back));

My question for this problem is how to handle click events for this navigation icon? This icon also disappears when toolbar colapses and leaves the left padding like it's there, but it's not.

Here's my code:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.darioradecic.topmusicandartists.Details">


    <android.support.design.widget.AppBarLayout
        android:id="@+id/MyAppbar"
        android:layout_width="match_parent"
        android:layout_height="256dp"
        android:fitsSystemWindows="true">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapse_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="@color/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <com.android.volley.toolbox.NetworkImageView
                android:id="@+id/imageViewDetailsTopGlobalSongs"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                app:layout_collapseMode="pin" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/tToolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"

                />
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="fill_vertical"
        android:padding="10dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

What am I doing wrong?

Reverse Proxy using java for multiple targets

I need to implement a reverse proxy using java which will support multiple targets. Target for a particular request should be identified from the request(e.g. from the request header).

I have got an example from https://hc.apache.org/httpcomponents-core-ga/httpcore/examples/org/apache/http/examples/ElementalReverseProxy.java link and it is working fine for a single target. I tried to update on that code to create the inconn and outconn in the run method of RequestListenerThread class instead of it's constructor but while trying to obtain the request header for an incoming request using inconn.receiveRequestHeader() then it is returning null after the first request.

    public void run() {
        System.out.println("Listening on port " + this.serversocket.getLocalPort());
        while (!Thread.interrupted()) {
            try {
                // Set up HTTP protocol processor for incoming connections
                final HttpProcessor inhttpproc = new ImmutableHttpProcessor(
                        new HttpRequestInterceptor[] {
                                new RequestContent(true),
                                new RequestTargetHost(),
                                new RequestConnControl(),
                                new RequestUserAgent("Test/1.1"),
                                new RequestExpectContinue(true)
                 });

                // Set up HTTP protocol processor for outgoing connections
                final HttpProcessor outhttpproc = new ImmutableHttpProcessor(
                        new HttpResponseInterceptor[] {
                                new ResponseDate(),
                                new ResponseServer("Test/1.1"),
                                new ResponseContent(),
                                new ResponseConnControl()
                });

                final int bufsize = 8 * 1024;
                // Set up incoming HTTP connection
                final Socket insocket = this.serversocket.accept();
                final DefaultBHttpServerConnection inconn = new DefaultBHttpServerConnection(bufsize);
                System.out.println("Incoming connection from " + insocket.getInetAddress());
                inconn.bind(insocket);

                HttpRequest request = inconn.receiveRequestHeader();

                Header[] rawCookie = request.getHeaders("Cookie");

                // Set up outgoing request executor
                final HttpRequestExecutor httpexecutor = new HttpRequestExecutor();

                // Set up incoming request handler
                final UriHttpRequestHandlerMapper reqistry = new UriHttpRequestHandlerMapper();
                reqistry.register("*", new ProxyHandler(
                        this.targetList.get(0),
                        outhttpproc,
                        httpexecutor));

                // Set up the HTTP service
                this.httpService = new HttpService(inhttpproc, reqistry);

                // Set up outgoing HTTP connection
                final Socket outsocket = new Socket(this.targetList.get(0).getHostName(), this.targetList.get(0).getPort());
                final DefaultBHttpClientConnection outconn = new DefaultBHttpClientConnection(bufsize);
                outconn.bind(outsocket);
                System.out.println("Outgoing connection to " + outsocket.getInetAddress());

                // Start worker thread
                final Thread t = new ProxyThread(this.httpService, inconn, outconn);
                t.setDaemon(true);
                t.start();
            } catch (final InterruptedIOException ex) {
                break;
            } catch (final IOException e) {
                System.err.println("I/O error initialising connection thread: "
                        + e.getMessage());
                break;
            }
        }
    } 

My intention was to use the target HttpHost in the UriHttpRequestHandlerMapper and in the outsocket based on the request cookie. Now can someone please advise if I am not taking the right approach or any other ways to fulfill my requirement?

Android: How to refresh online data when Internet is available without creating a new Fragment?

When my MainFragment first loads, it checks for internet connectivity. If there is internet, it loads the content from online. However, if there is no internet connectivity, I replace the existing fragment MainFragment within the container main_browse_fragment with InternetConnectivityFragment.

Within InternetConnectivtyFragment, I have a Retry button that re-checks the internet, and if there is internet connectivity, I remove InternetConnectivityFragment and call popbackstack.

The problem is, when popbackstack is called, I dont know how to reload the online data from within MainFragment. The online data loading and internet check is done within onActivityCreated of MainFragment.java, but when popbackstack is called within InternetConnectivityFragment.java, the view of MainFragment is blank

Obviously this is because the fragment is not "created" and onActivityCreated is not called again, so no data is reloaded.

Here's the relevant code:

MainFragment.java:

public class MainFragment extends DetailsFragment
{
    @Override
    public void onActivityCreated(Bundle savedInstanceState)
    {
        super.onActivityCreated(savedInstanceState);

        setupUIElements();

        if (isConnectingToInternet() == true)
        {
            // Call methods to load online data
        }
        else
        {
            InternetConnectivityFragment internetError = new InternetConnectivityFragment();

            getFragmentManager().beginTransaction().add(R.id.main_browse_fragment, internetError).commit();
        }
    }

    ...
}

InternetConnectivityFragment.java:

public class InternetConnectivityFragment extends ErrorFragment
{
    private static final String TAG = "InternetFragment";
    private static final boolean TRANSLUCENT = true;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        setErrorContent();
    }

    private void setErrorContent()
    {
        setImageDrawable(getResources().getDrawable(R.drawable.lb_ic_sad_cloud, null));
        setMessage(getResources().getString(R.string.no_internet_message));
        setDefaultBackground(TRANSLUCENT);

        setButtonText(getResources().getString(R.string.retry_connection));

        setButtonClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View arg0)
            {

                if (Singleton.getInstance().isConnectedToInternet()  == true)
                {
                    getFragmentManager().beginTransaction().remove(InternetConnectivityFragment.this).commit();
                    getFragmentManager().popBackStack();

                    // How to call methods to re-load online data from MainFragment????
                }
            }
        });
    }
}

I have tried to perform the following within the onClick method:

MainFragment mainFragment = new MainFragment();

getFragmentManager().beginTransaction().remove(InternetConnectivityFragment.this).commit();
getFragmentManager().popBackStack();
getFragmentManager().beginTransaction().add(R.id.main_browse_fragment, mainFragment).commit();

However, I believe this is wrong as it just adds a new fragment MainFragment on top of an already existing fragment.

Can someone point me in the right direction?

Thanks

Saving an entity with composite key via JPA+Hibernate results in exception

Here is my entity:

@Entity
@Table(name = "foo.bar")
public class Foobar implements Serializable {

    private static final long   serialVersionUID    = 1L;

    @Id
    @Column(name = "fk_ruleId")
    private Long                ruleId;

    @Id
    @Column(name = "fk_storageId")
    private Long                storageId;

    @Id
    @Column(name = "logicalDestination")
    private String              logicalDestination;

    public Long getRuleId() {
        return ruleId;
    }

    public void setRuleId(Long ruleId) {
        this.ruleId = ruleId;
    }

    public Long getStorageId() {
        return storageId;
    }

    public void setStorageId(Long storageId) {
        this.storageId = storageId;
    }

    public String getLogicalDestination() {
        return logicalDestination;
    }

    public void setLogicalDestination(String logicalDestination) {
        this.logicalDestination = logicalDestination;
    }

} // end class

And here is the appropriate create table statement (MS SQL):

CREATE TABLE [foo].[bar](
    [fk_ruleId] [numeric](19, 0) NOT NULL,
    [fk_storageId] [int] NOT NULL,
    [logicalDestination] [varchar](10) NOT NULL,
 CONSTRAINT [PK_foobar] PRIMARY KEY CLUSTERED 
(
    [fk_ruleId] ASC,
    [fk_storageId] ASC,
    [logicalDestination] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

I'm trying to save an entity with the following snippet:

Foobar newMapElement = new Foobar();
        newMapElement.setLogicalDestination("6");
        newMapElement.setStorageId(4l);
        newMapElement.setRuleId(3l);

        service.saveMap(newMapElement);

where service resolves to:

em.persist(newMapElement);

The mapping itseld seems to be fine. However, trying to save results is an exception:

com.microsoft.sqlserver.jdbc.SQLServerException: Index "4" is out of range.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:190)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.setterGetParam(SQLServerPreparedStatement.java:714)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.setValue(SQLServerPreparedStatement.java:723)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.setString(SQLServerPreparedStatement.java:1048)
    at org.jboss.jca.adapters.jdbc.CachedPreparedStatement.setString(CachedPreparedStatement.java:195)
    at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.setString(WrappedPreparedStatement.java:637)
    at org.hibernate.type.descriptor.sql.VarcharTypeDescriptor$1.doBind(VarcharTypeDescriptor.java:57) [hibernate-core-4.2.15.Final.jar:4.2.15.Final]
    at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:93) [hibernate-core-4.2.15.Final.jar:4.2.15.Final]
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:284) [hibernate-core-4.2.15.Final.jar:4.2.15.Final]
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:279) [hibernate-core-4.2.15.Final.jar:4.2.15.Final]
    at org.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:343) [hibernate-core-4.2.15.Final.jar:4.2.15.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.dehydrateId(AbstractEntityPersister.java:2835) [hibernate-core-4.2.15.Final.jar:4.2.15.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2804) [hibernate-core-4.2.15.Final.jar:4.2.15.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3076) [hibernate-core-4.2.15.Final.jar:4.2.15.Final]
    ... 109 more

Why is that??

Thanks in advance!