How to get current page URL with gecko? - java

I am trying to make my android web browser open only specific urls. Because of that, I want to check if loaded url meets the requirements, and according to that to do something. I saw many answers about WebView, but since I have to use open source browser (Mozilla Firefox) I am using gecko. Here is my code, I tried to do something with onLoadRequest but I do not know how to make it work. Thanks.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GeckoView view = findViewById(R.id.geckoView);
GeckoSession session = new GeckoSession();
GeckoRuntime runtime = GeckoRuntime.create(this);
session.open(runtime);
view.setSession(session);
session.loadUri("https://www.google.com");
GeckoSession.NavigationDelegate.LoadRequest loadRequest=new GeckoSession.NavigationDelegate.LoadRequest();
session.getNavigationDelegate().onLoadRequest(session,loadRequest);
}
#Override
public void onLoadRequest(GeckoSession session, GeckoSession.NavigationDelegate.LoadRequest request)
{
if(request.uri.contains("mail"))
GeckoResult.fromValue(AllowOrDeny.ALLOW);
else
GeckoResult.fromValue(AllowOrDeny.DENY);
}

GeckoView heavily relies on its delegates to allow for app-specific handling of most relevant mechanics and events.
In short, there are runtime and session delegates, set on GeckoRuntime and GeckoSession respectively.
The general pattern is that for each delegate there is a set{DelegateName}Delegate() method to attach delegates to the runtime or session with one exception being RuntimeTelemetry.Delegate which is set in GeckoRuntimeSettings instead.
Delegate methods are called by GeckoView and should not be called by the app.
In your case, you want to implement the NavigationDelegate and set your implementation on the GeckoSession to override the default top-level page load behavior.
class MyNavigationDelegate implements GeckoSession.NavigationDelegate {
#Override
public GeckoResult<AllowOrDeny> onLoadRequest(
final GeckoSession session,
final LoadRequest request) {
// TODO: deny/allow based on your constrains.
}
// TODO: You should implement the rest of the delegate to handle page load
// errors and new session requests triggered by new-tab/window requests.
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GeckoView view = findViewById(R.id.geckoView);
GeckoSession session = new GeckoSession();
GeckoRuntime runtime = GeckoRuntime.create(this);
session.setNavigationDelegate(new MyNavigationDelegate());
session.open(runtime);
view.setSession(session);
session.loadUri("https://www.google.com");
}
For more details, please consult the API reference and the GeckoView Example implementation.

Related

Cannot use Toothpick.inject in Fragment

I'm getting strange error while trying to use Toothpick DI in a fragment:
toothpick.registries.NoFactoryFoundException: No factory could be found for class android.app.Application. Check that the class has either a #Inject annotated constructor or contains #Inject annotated members. If using Registries, check that they are properly setup with annotation processor arguments.
My fragment:
public class ApplicationMenu extends SidebarFragment {
#Inject ApplicationsService applicationsService;
#Inject SectionsService sectionsService;
private EventBus bus = EventBus.getDefault();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toothpick.inject(this, Toothpick.openScope(LauncherActivity.class)); // <- Erroring here
}
...
}
Activity:
public class LauncherActivity extends SidebarActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
Scope scope = Toothpick.openScopes(LauncherApplication.class, LauncherActivity.class);
scope.bindScopeAnnotation(LauncherActivitySingleton.class);
scope.installModules(new LauncherActivityModule(this));
super.onCreate(savedInstanceState);
Toothpick.inject(this, scope);
setContentView(R.layout.activity_launcher);
ButterKnife.bind(this);
...
}
...
}
The strange thing is I get the error only in fragments, all injections in other places (ViewRenderers, Adapters, Services etc) work fine with no problem
I figured that out. I close the application scope in one of my services by mistake. That service was using in fragments which cases the error.
Unfortunately the error message does not provide any useful information and the only way to find the problem is to analyze and debug all the code.
So using the toothpick di you have to be very careful with scope life-cycle.

I am trying to run the code inside the onMenuItemClick() without pressing the menu button

This is the code for android activity I want to run, if at all possible without creating a new activity. Need to get rid of the Listener function. I tried to make a new java class but it gave me error on putExtra functions. Also how can I deal with the instance of newConnection inside the Listener constructor.
public class NewConnection extends Activity {
private Bundle result = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
private class Listener implements OnMenuItemClickListener {
//used for starting activities
private NewConnection newConnection = null;
public Listener(NewConnection newConnection)
{
this.newConnection = newConnection;
}
Trying to run the code below without clicking:
#Override
public boolean **onMenuItemClick**(MenuItem item) {
{
// this will only connect need to package up and sent back
Intent dataBundle = new Intent();
String server = ("tsp//:server address");
String port = ("1823");
//put data into a bundle to be passed back to ClientConnections
dataBundle.putExtra(ActivityConstants.server, server);
dataBundle.putExtra(ActivityConstants.port, port);
...
...
//add result bundle to the data being returned to ClientConnections
dataBundle.putExtras(result);
setResult(RESULT_OK, dataBundle);
newConnection.finish();
}
return false;
}
This is the code used to call the activity:
createConnection = new Intent();
createConnection.setClassName(
clientConnections.getApplicationContext(),
"org.eclipse.paho.android.service.sample.NewConnection");
clientConnections.startActivityForResult(createConnection,
ActivityConstants.connect);
This is a basic constructor within a listener paradigm. It's a core idea within computer science that code should be reusable, and to facilitate this code needs to generally be self contained. This is often done within Java with a listener. It's usually an abstract class or an interface that has a few set functions. The main class that uses the listener is assigned this object or objects, and when it reaches a relevant point will trigger the listener to notify your code of an event.
This allows people to write code that is fully contained and still provide event hooks whereby other user who employ that code can get feedback such as when a menu item is clicked or a new connection is made, and have this dealt with by the person using this code, but without the author of the original class knowing anything about your code. It allows things like menus and connection managers and buttons that have no connection to the code that they trigger, by design. So that any number of these can be made and used.

Android: Fragments, SQLite and Loaders

So I've come to a point where I need to implement an SQLite database for my app.
Following "The Busy Coder's guide to Android Development" I have created a DatabaseHelper class that extends SQLiteOpenHelper.
One of my use cases is to run a query against the database and display the results on a ListView within a Fragment (I use fragments from the support library).
From what I understand, using managedQuery() is not really appropriate and even if it were it isn't recommended due to the fact that some of the logic encapsulated inside this method is actually executed on the main thread, specifically reQuery() which to my understanding is performed when the Activity is restarted.
So I've been trying to get acquainted with the Loader class for the first time, only to see this:
"The only supplied concrete implementation of a Loader is CursorLoader, and that is only for use with a ContentProvider"
My initial thought was to implement my own content provider and perhaps prevent other apps from getting access to it, then I read the following in the ContentProvider documentation via developer.android.com:
"You don't need a provider to use an SQLite database if the use is entirely within your own application."
I've also been playing with this:
https://github.com/commonsguy/cwac-loaderex
Yet I am not familiar with this project, and not sure if it can be used on a production environment.
So, right now all I can think of is creating a bunch of AsyncTask instances within my Fragment and manage their lifecycle appropriately, make sure they're cancelled whenever needed and whatnot.
Are there any other options?
I think implementing content provider is a good idea, no matter that data will not be accessible outside of the application. It provides very modern interface and from my experience makes your application error prone to database locking issues and other db-specific problems.
I've implemented it in my latest project and I was very happy to use it.
You can extend Loader class in order to perform other Async work such as loading directly from your DB.
Here is an example of that
Edit: added A better example of Loader usage.
Finally managed to find the tutorial that really helped me understand how things work.
By extending the loader class you can avoid messing with content observers and its quite easy to implement (at last)
the modifications that need to be taken in your code are
Add implementation of LoaderManager.LoaderCallbacks<D>, where D is your data list (snippet 1)
Create your loader class, copy snippet 2, and add the loading of your data from the DB
Finally call the loaders 1 call for init and then for refreshing the restart call. (snippet 2 & 3)
Snippet 1: How to "link" the loader with your fragment:
public static class AppListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<List<SampleItem>> {
public Loader<List<SampleItem>> onCreateLoader(int id, Bundle args) {
//...
return new SampleLoader (getActivity());
}
public void onLoadFinished(Loader<List<SampleItem>> loader, List<SampleItem> data) {
// ...
mAdapter.setData(data);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
// ...
}
public void onLoaderReset(Loader<List<SampleItem>> loader) {
// ...
mAdapter.setData(null);
// ...
}
/* ... */
}
Snippet 2: Schema of your custom loader: (I have double commented the observer things as I believe that it is quite difficult to implement it from the beginning and you can simple recall the loader without messing with that automated refreshing)
public class SampleLoader extends AsyncTaskLoader<List<SampleItem>> {
// We hold a reference to the Loader’s data here.
private List<SampleItem> mData;
public SampleLoader(Context ctx) {
// Loaders may be used across multiple Activitys (assuming they aren't
// bound to the LoaderManager), so NEVER hold a reference to the context
// directly. Doing so will cause you to leak an entire Activity's context.
// The superclass constructor will store a reference to the Application
// Context instead, and can be retrieved with a call to getContext().
super(ctx);
}
/****************************************************/
/** (1) A task that performs the asynchronous load **/
/****************************************************/
#Override
public List<SampleItem> loadInBackground() {
// This method is called on a background thread and should generate a
// new set of data to be delivered back to the client.
List<SampleItem> data = new ArrayList<SampleItem>();
// TODO: Perform the query here and add the results to 'data'.
return data;
}
/********************************************************/
/** (2) Deliver the results to the registered listener **/
/********************************************************/
#Override
public void deliverResult(List<SampleItem> data) {
if (isReset()) {
// The Loader has been reset; ignore the result and invalidate the data.
releaseResources(data);
return;
}
// Hold a reference to the old data so it doesn't get garbage collected.
// We must protect it until the new data has been delivered.
List<SampleItem> oldData = mData;
mData = data;
if (isStarted()) {
// If the Loader is in a started state, deliver the results to the
// client. The superclass method does this for us.
super.deliverResult(data);
}
// Invalidate the old data as we don't need it any more.
if (oldData != null && oldData != data) {
releaseResources(oldData);
}
}
/*********************************************************/
/** (3) Implement the Loader’s state-dependent behavior **/
/*********************************************************/
#Override
protected void onStartLoading() {
if (mData != null) {
// Deliver any previously loaded data immediately.
deliverResult(mData);
}
// Begin monitoring the underlying data source.
////if (mObserver == null) {
////mObserver = new SampleObserver();
// TODO: register the observer
////}
//// takeContentChanged() can still be implemented if you want
//// to mix your refreshing in that mechanism
if (takeContentChanged() || mData == null) {
// When the observer detects a change, it should call onContentChanged()
// on the Loader, which will cause the next call to takeContentChanged()
// to return true. If this is ever the case (or if the current data is
// null), we force a new load.
forceLoad();
}
}
#Override
protected void onStopLoading() {
// The Loader is in a stopped state, so we should attempt to cancel the
// current load (if there is one).
cancelLoad();
// Note that we leave the observer as is. Loaders in a stopped state
// should still monitor the data source for changes so that the Loader
// will know to force a new load if it is ever started again.
}
#Override
protected void onReset() {
// Ensure the loader has been stopped.
onStopLoading();
// At this point we can release the resources associated with 'mData'.
if (mData != null) {
releaseResources(mData);
mData = null;
}
// The Loader is being reset, so we should stop monitoring for changes.
////if (mObserver != null) {
// TODO: unregister the observer
//// mObserver = null;
////}
}
#Override
public void onCanceled(List<SampleItem> data) {
// Attempt to cancel the current asynchronous load.
super.onCanceled(data);
// The load has been canceled, so we should release the resources
// associated with 'data'.
releaseResources(data);
}
private void releaseResources(List<SampleItem> data) {
// For a simple List, there is nothing to do. For something like a Cursor, we
// would close it in this method. All resources associated with the Loader
// should be released here.
}
/*********************************************************************/
/** (4) Observer which receives notifications when the data changes **/
/*********************************************************************/
// NOTE: Implementing an observer is outside the scope of this post (this example
// uses a made-up "SampleObserver" to illustrate when/where the observer should
// be initialized).
// The observer could be anything so long as it is able to detect content changes
// and report them to the loader with a call to onContentChanged(). For example,
// if you were writing a Loader which loads a list of all installed applications
// on the device, the observer could be a BroadcastReceiver that listens for the
// ACTION_PACKAGE_ADDED intent, and calls onContentChanged() on the particular
// Loader whenever the receiver detects that a new application has been installed.
// Please don’t hesitate to leave a comment if you still find this confusing! :)
////private SampleObserver mObserver;
}
Snippet 3: How to call the loader for the first time (ONLY)
// Initialize a Loader with an id. If the Loader with this id is not
// initialized before
getLoaderManager().initLoader(LOADER_ID, null, this);
Snippet 4: For refreshing data (recalling the query)
// Check if the loader exists and then restart it.
if (getLoaderManager().getLoader(LOADER_ID) != null)
getLoaderManager().restartLoader(LOADER_ID, null, this);
Reference:
Snippet 1 : usage of loader extracted from here
Snippet 2 : here for more info and logic read throughout the hole article
Snippet 3 & 4: are just loader usage.
Full code of these is also uploaded by the creator on github
I recommend OrmLite library, a lightweight Object Relational Mapping that can work for Android. This library will make your life easier . You don't need to create or update database by hand, you don't need to focus on managing database connection, all queries select, insert, update will be easier with a DAO approach (usually you don't need to write your own sql query) and a lot of features. They have some examples that you can start with.
And if you want to use the Loader, there is a ORMLite Extras , additional functionality for ORMLite available on github (You can use the support package which is compatible with support android library). Here is an example usage on my previous project:
public class EventsFragment extends Fragment implements LoaderCallbacks<Cursor>{
private static final int LOADER_ID = EventsFragment.class.getName().hashCode();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View layoutRoot = inflater.inflate(
R.layout.fragment_events, null);
lvEvents = (ListView) layoutRoot.findViewById(R.id.lvEvents);
adapter = new EventAdapter(getActivity(), null, null);
lvEvents.setAdapter(adapter);
return layoutRoot;
}
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
try {
PreparedQuery<Event> query = getDatabaseHelper().getEventDao().getQuery();
return getDatabaseHelper().getEventDao().getSQLCursorLoader(query );
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
adapter.swapCursor(cursor);
try {
adapter.setQuery(getDatabaseHelper().getEventDao().getQuery());
} catch (SQLException e) {
e.printStackTrace();
}
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
adapter.swapCursor(null);
}
private OrmliteDatabaseHelper getDatabaseHelper(){
return ((MainActivity)getActivity()).getDatabaseHelper();
}
}
The adapter
public class EventAdapter extends OrmliteCursorAdapter<Event>{
public EventAdapter(Context context, Cursor c, PreparedQuery<Event> query) {
super(context, c, query);
}
#Override
public void bindView(View itemView, Context context, Event item) {
TextView tvEventTitle = (TextView) itemView.findViewById(R.id.tvEventTitle);
TextView tvEventStartDate = (TextView) itemView.findViewById(R.id.tvEventStartDate);
tvEventTitle.setText(item.getTitle());
tvEventStartDate.setText(item.getFormatStartDate());
}
#Override
public View newView(Context context, Cursor arg1, ViewGroup arg2) {
LayoutInflater inflater = LayoutInflater.from(context);
View retView = inflater.inflate(R.layout.event_item_row, arg2, false);
return retView;
}
}
And a custom Dao which provides PreparedQuery for cursor adapter above:
public interface IEventDao extends Dao<Event, Integer>{
PreparedQuery<Event> getQuery() throws SQLException;
OrmliteCursorLoader<Event> getSQLCursorLoader(Context context, PreparedQuery<Event> query) throws SQLException;
}
public class EventDao extends AndroidBaseDaoImpl<Event, Integer> implements IEventDao{
public EventDao(ConnectionSource connectionSource) throws SQLException {
super(connectionSource, Event.class);
}
public EventDao(ConnectionSource connectionSource,
DatabaseTableConfig<Event> tableConfig) throws SQLException {
super(connectionSource, tableConfig);
}
#Override
public PreparedQuery<Event> getQuery() throws SQLException{
return queryBuilder().prepare();
}
}
Hope this can help!
If your database contains thousands of records consider madlymad's answer
If not keep it stupid and simple, use SQLiteOpenHelper and create a method that returns you your data as array of strings or define your one objects.
Also use custom/regular CursorAdapter or ArrayAdapter.
I use the SQLiteOpenHelper to create my database. I have made Java classes for all the tables and when I get the data from my database I put it in an ArrayList. The ArrayList I then load into the adapter of the Listview.

How can these two json be different?

I am using volley with android. As I am studying this example on github https://github.com/evancharlton/folly . That project made a perfect solution of querying json.
Now comes the problem. If I replace the json url there with another, then the fetching seems not to work!
I know different jsonws need different parsing jobs so I extremely simplified the code. Like this.
public class MainActivity extends SherlockFragmentActivity {
/**
* Called when the activity is first created.
*/
private ViewPager pager;
private PagerSlidingTabStrip tabs;
private MyPagerAdapter adapter;
private String url = "http://konachan.com/post.json?limit=1";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView txt = (TextView) findViewById(R.id.text);
txt.setText("initial");
RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
public void onResponse(JSONObject response) {
txt.setText("somethinghappend");
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
Log.e("wtf", error.toString()) ;
}
});
queue.add(jsObjRequest);
}
}
As you can tell, I removed everything about the content of json but only doing this to figure out why the code goes wrong with only one change: the url
To make it clear:(i dont have enough reputation for multi links so use the comment insdead)
when I set url to
(comment 1)
my TextView successfully change his text(this is the json used in the example project from github, though this is meaningless information since I had built very unrelated code from the example)
but when I switch the address to
(comment 2)
nothing happen to my TextView!(this is the json I really need to work with)
And yes, both jsons are correctly fetched and parsed and displayed in firefox(without any kind of proxy), so I think there are nothing wrong with the jsons and the network.
In fact I think the ONLY difference is that they are different jsons.... with 2 different urls....
Now I seek help from you guys, how can that be? Nothing changed but only a smaller json.. makes everything broken? (is it about timeout matters? but both are loaded very fast in firefox... and obviously the working one contains much more bytes than the not working one...)
the error logged 410 error. The page has Gone?! But it is alive in firefox... and the other json works in both environment(firefox and app)

Logging switch realization

This code:
public class MyActivity extends Activity {
private final boolean logging = getResources().getBoolean(R.bool.logging);
#Override
public void onCreate(Bundle savedInstanceState) {
if(logging) Log.d("my_log", "some text here");
// some onCreate code...
}
}
generates NullPointerException.
But this one:
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
final boolean logging = getResources().getBoolean(R.bool.logging);
if(logging) Log.d("my_log", "some text here");
// some onCreate code...
}
}
Does not.
The main idea to switch logging in entire application with a boolean resource.
I can successfully declare this variable for every function in class, but can it be done for entire class just once?
Have you considered using a proper logging framework?
If you use the slf4j API you can write stuff like
log.debug("A={}, B={}", a, b)
where the switch is externally set in a well-documented way whether to generate a log statement or not. Also the slf4j {}-construct allows delaying the call to a.toString() and b.toString() until after the logging framework has decided that the log message actually needs to be generated.
slf4j is an API. You have several backends to choose from. For starters you can just pick the "simple" backend.
See http://slf4j.org/manual.html for an introduction.
Instead of putting value to string resource, I used static variable in special class.
public class constants {
public static final boolean logging = true;
}
so it can be accessed from any activity:
private boolean logging = constants.logging;

Categories