вторник, 17 декабря 2013 г.

Using InputStream with MultipartEntityBuilder

Hello all!
Few days ago i had a simple task: send image file to web server. I found apache lib with MultipartEntityBuilder class - it seems to be popular among coders.
It has method that seems to allow using InputStream. But it does not work!

Here is the code that DOES NOT work, and I don't know why:


   
HttpClient httpclient = new DefaultHttpClient();
JSONObject result;
HttpPost httppost = new HttpPost("http://www.ezduki.ru/api/content/add/image/");
InputStream iStream = con.getContentResolver().openInputStream(imageUri);
MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();
multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.addTextBody("token", code);
multipartEntity.addBinaryBody("file", iStream);
httppost.setEntity(multipartEntity.build());
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
result = new JSONObject(EntityUtils.toString(entity));
 
I did not find the way to make it work with InputStream correctly: 
web server gives an error, POST message is wrong. So I did it my way:

 
   
        MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();
        multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        multipartEntity.addTextBody("token", code);

        InputStream iStream = con.getContentResolver().openInputStream(imageUri);
        // saving temporary file
        String filePath = saveStreamTemp(iStream);
        File f = new File(filePath);
        multipartEntity.addPart("file", new FileBody(f));
        httppost.setEntity(multipartEntity.build());
        HttpResponse response = httpclient.execute(httppost);
        HttpEntity entity = response.getEntity();
        result = new JSONObject(EntityUtils.toString(entity));
        f.delete();

    String saveStreamTemp(InputStream fStream){
    final File file;
    try {
        String timeStamp =
                new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

        file = new File(con.getCacheDir(), "temp_"+timeStamp + ".jpg");
        final OutputStream output;
        try {
            output = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return "";
        }
        try {
            try {
                final byte[] buffer = new byte[1024];
                int read;

                while ((read = fStream.read(buffer)) != -1)
                    output.write(buffer, 0, read);

                output.flush();
            } finally {
                output.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    } finally {
        try {
            fStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    return file.getPath();
}
 

четверг, 17 ноября 2011 г.

Using AndEngine and physicsbox2d







AndEngine is one of the most popular free game engine for Android. Physicsbox2d seems to be powerful toll to create physics world in you game. It's easy to use them together, and I want to show you, how to:

1. Create Android project. Add libs andengine.jar, andenginephysicsbox2dextension.jar,
and folder armeabi that contains files libandenginephysicsbox2dextension.so, armeabilibxmp.so.

2. Inherit your activity class from BaseGameActivity, implement onLoadEngine and onLoadScene. Here is the code with comments:

   
public class MainActivity extends BaseGameActivity
{
    // Camera screen width
    private static final int CAMERA_WIDTH = 800;
    // Camera screen height
    private static final int CAMERA_HEIGHT = 480;
    // Physics Environment parameters
    private static final FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f);
    // Camera to look at world
    private Camera mCamera;
    // Scene, we look at through camera
    private Scene mScene;
    // Physical world
    private PhysicsWorld mPhysicsWorld;
    
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
    }

    // Loading engine
    public Engine onLoadEngine() {
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
        return new Engine(new EngineOptions(true, ScreenOrientation.PORTRAIT,
                new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),
                this.mCamera));
    }

    public void onLoadResources() {
    }

    public Scene onLoadScene() {
        // Creating new one-layer scene
        mScene = new Scene(1);
        // Creating physical world with gravity
        this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
        mScene.registerUpdateHandler(mPhysicsWorld);
        return mScene;
    }

    public void onLoadComplete() {
    }
}


After starting project, we see friendly vacuum, our world is still empty.

2. Adding textures. We'll make special class for that. It's good idea to use static methods.

  
public class Textures {

    private Texture mTexture;
    private static TextureRegion mBallTextureRegion;
    private static TextureRegion mBackgroundTextureRegion;

    public Textures(final BaseGameActivity activity, final Engine engine) {
        // Atlas for textures
        mTexture = new Texture(1024, 1024,
                TextureOptions.BILINEAR_PREMULTIPLYALPHA);

        // Image size - 512x1024.
        mBackgroundTextureRegion = TextureRegionFactory.createFromAsset(
                mTexture, activity, "gfx/bkg.png", 0, 0);
        mBallTextureRegion = TextureRegionFactory.createFromAsset(
                mTexture, activity, "gfx/ball.png", 512, 0);

        engine.getTextureManager().loadTexture(mTexture);
    }

    public static TextureRegion getBackground() {
        return mBackgroundTextureRegion;
    }

    public static TextureRegion getBallTextureRegion() {
        return mBallTextureRegion;
    }
}



3. Initializing this object in activity

   
public void onLoadResources() {
        mTextures = new Textures(this, getEngine());
    }


4. And the last thing: fill Scene with sprites and objects.
   
public Scene onLoadScene() {
        mScene = new Scene(1);
        this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
        mScene.setBackground(new SpriteBackground(new Sprite(0, 0, Textures.getBackground())));
        
        // Lines will be borders
        Line line_top = new Line(0, 0, CAMERA_WIDTH, 0, 5.0f * metrics.density);
        Line line_left = new Line(0, 0, 0, CAMERA_HEIGHT, 5.0f * metrics.density);
        Line line_right = new Line(CAMERA_WIDTH, 0, CAMERA_WIDTH, CAMERA_HEIGHT, 5.0f * metrics.density);
        Line line_bottom = new Line(0, CAMERA_HEIGHT, CAMERA_WIDTH, CAMERA_HEIGHT, 5.0f * metrics.density);
        // Physical bodies based on lines
        Body wall_top = PhysicsFactory.createLineBody(mPhysicsWorld, line_top, FIXTURE_DEF);
        Body wall_left = PhysicsFactory.createLineBody(mPhysicsWorld, line_left, FIXTURE_DEF);
        Body wall_right = PhysicsFactory.createLineBody(mPhysicsWorld, line_right, FIXTURE_DEF);
        Body wall_bottom = PhysicsFactory.createLineBody(mPhysicsWorld, line_bottom, FIXTURE_DEF);

        // Ball sprite
        Sprite mSprite = new Sprite(0.0f, 0.0f, 100, 100, Textures.getBallTextureRegion());
        mSprite.setPosition(100, 100);
        // Ball body
        Body mBody = PhysicsFactory.createCircleBody(mPhysicsWorld, 100, 100, 50, 0, BodyType.DynamicBody, FIXTURE_DEF);
               
        // Connecting sprites with physical bodies
        this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(line_top, wall_top, true, true));
        this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(line_left, wall_left, true, true));
        this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(line_right, wall_right, true, true));
        this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(line_bottom, wall_bottom, true, true));
        mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(mSprite, mBody, true, true));
        
        // Attaching sprites to scene
        this.mScene.attachChild(mSprite);
        this.mScene.attachChild(line_top);
        this.mScene.attachChild(line_left);
        this.mScene.attachChild(line_right);
        this.mScene.attachChild(line_bottom);
 
        mScene.registerUpdateHandler(mPhysicsWorld);
        return mScene;
    }



That's all! Start project, and you see ball, falling and jumping according to physics laws.

воскресенье, 23 октября 2011 г.

Android: computing speed and distance using accelerometer






It's possible to compute distance and speed using only accelerometer, but with three conditions:
1. Linear movement - trajectory must be straight.
2. Slope of the road must be constant.
3. You must perform calibration procedure before start.

Where can you use this method with such restrictions - it's up to you... Now, how to do it:

1. We need something, implementing SensorEventListener interface. For the future use, let's add following abstract class:
  
public abstract class Accelerometer implements SensorEventListener {

    protected float lastX;
    protected float lastY;
    protected float lastZ;
    public abstract Point getPoint();
    public void onAccuracyChanged(Sensor arg0, int arg1) {
    }
}
 

and this will be our SensorEventListener:

  
public class XYZAccelerometer extends Accelerometer {
  
    
    private static final int BUFFER_SIZE = 500;
    // calibration
    private  float dX = 0;
    private  float dY = 0;
    private  float dZ = 0;
    // buffer variables
    private float X;
    private float Y;
    private float Z;
    private int cnt = 0;
    
    // returns last SenorEvent parameters
    public Point getLastPoint(){
        return new Point(lastX, lastY, lastZ, 1);
    }

    // returrns parameters, using buffer: average acceleration
    // since last call of getPoint(). 
    public Point getPoint(){
        
        if (cnt == 0){
            return new Point(lastX, lastY, lastZ, 1);
        }
                
        Point p =  new Point(X, Y, Z, cnt);
        
        reset();
        return p;
    }
    
    // resets buffer
    public void reset(){
        cnt = 0;
        X = 0;
        Y = 0;
        Z = 0;
    }
    
    
    public void onSensorChanged(SensorEvent se) {
        float x = se.values[SensorManager.DATA_X] + dX;
        float y = se.values[SensorManager.DATA_Y] + dY;
        float z = se.values[SensorManager.DATA_Z] + dZ;
        
        lastX = x;
        lastY = y;
        lastZ = z;
        
        X+= x;
        Y+= y;
        Z+= z;
        
        if (cnt < BUFFER_SIZE-1) {
            cnt++;
        } else
        {
            reset();
        }
    }

    public int getCnt(){
        return cnt;
    }

    public  void setdX(float dX) {
        this.dX = dX;
    }

    public  void setdY(float dY) {
        this.dY = dY;
    }

    public  void setdZ(float dZ) {
        this.dZ = dZ;
    }
}
 

Calibrating accelerometer must be called before each experiment. Phone orientation must not be changed while measuring.

To calibrate accelerometer, i use this class:

  
public class Calibrator {

    final static int UPDATE_INTERVAL = 400;
    final static int ITERATIONS = 5;
    Handler hRefresh;
    XYZAccelerometer acc;
    int eventNumber;
    private LinkedList calData;

    public Calibrator(Handler hRefresh, XYZAccelerometer acc, int eventNumber) {
        this.hRefresh = hRefresh;
        this.acc = acc;
        this.eventNumber = eventNumber;
    }

    public void calibrate() {
        final Timer calTimer = new Timer();
        calData = new LinkedList();
        acc.setdX(0);
        acc.setdY(0);
        acc.setdZ(0);

        calTimer.scheduleAtFixedRate(
                new TimerTask() {

                    public void run() {
                        addCalData(calData);
                        if (calData.size() > ITERATIONS) {
                            calTimer.cancel();
                            try {
                                calSensor(calData);
                            } catch (Exception ex) {
                                try {
                                    throw ex;
                                } catch (Exception ex1) {
                                     hRefresh.sendEmptyMessage(5);
                                }
                            }
                            hRefresh.sendEmptyMessage(eventNumber);
                        }
                    }
                },
                0,
                UPDATE_INTERVAL);
    }

    private void addCalData(LinkedList cD) {
        Point p = acc.getPoint();
        cD.add(p);
        acc.reset();
    }

    private void calSensor(LinkedList cD) throws Exception {
        if (cD.size() < ITERATIONS-1) {
            throw new Exception("not enough data to calibrate");
        }
        float x = 0;
        float y = 0;
        float z = 0;
        // Don't use first measure
        for (int i = 1; i < cD.size(); ++i) {
            x += cD.get(i).getX();
            y += cD.get(i).getY();
            z += cD.get(i).getZ();
        }

        x = x / (cD.size() - 1);
        y = y / (cD.size() - 1);
        z = z / (cD.size() - 1);

        acc.setdX(-x);
        acc.setdY(-y);
        acc.setdZ(-z);
    }
}

 

maintenance class to keep data of one measure

  
public class Point {
    private float x = 0;
    private float y = 0;
    private float z = 0;
    private int cnt = 1;

    public float getX() {
        return x/(float)cnt;
    }

    public float getY() {
        return y/(float)cnt;
    }

    public float getZ() {
        return z/(float)cnt;
    }

    public Point(float x, float y, float z, int cnt) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.cnt = cnt;
    }
    
    
    public float getForce(){
        return getX()*getX()+getY()*getY()+getZ()*getZ();
    }
}
 

And class to process data of measure
  
public class MeasurePoint {
    private float x;
    private float y;
    private float z;
    private float speedBefore;
    private float speedAfter;
    private float distance;
    private float acceleration;
    private long interval;
    private Point averagePoint;

    public MeasurePoint(float x, float y, float z, float speedBefore, long interval, Point averagePoint) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.speedBefore = speedBefore;
        this.interval = interval;
        this.averagePoint = averagePoint;
        speedAfter = 0;
        calc();
    }
    
    private void calc(){
        //Acceleration as projection of current vector on average
        acceleration = this.x*averagePoint.getX() +
                        this.y*averagePoint.getY() +
                        this.z*averagePoint.getZ();
        acceleration = acceleration / ((float)Math.sqrt(averagePoint.getForce()));
        float t = ((float)interval / 1000f);
        speedAfter = speedBefore + acceleration * t;
        distance = speedBefore*t + acceleration*t*t/2;
        
    }
    
    public String getStoreString(){
        String s = "write here whatever you want";
        return s;
    }

// add getters
}
 

This one - to store and save data array
  
public class MeasureData {
    // points from accelerometr
    private LinkedList accData;
    private LinkedList data;
    // timer interval of generating points
    private long interval;

    public MeasureData(long interval) {
        this.interval = interval;
        accData = new LinkedList ();
        data = new LinkedList ();
    }
    
    public void addPoint(Point p){
        accData.add(p);
    }
    
    public void process(){
        
        for(int i = 0; i < accData.size(); ++i){
            Point p = accData.get(i);
            float speed = 0;
            
            if(i > 0){
                speed = data.get(i-1).getSpeedAfter();
            }
            data.add(new MeasurePoint(p.getX(), p.getY(), p.getZ(), speed, interval, getAveragePoint()));
        }
    }
    
    public boolean saveExt(Context con, String fname) throws Throwable {

        try {

            File file = new File(con.getExternalFilesDir(null), fname);
            FileOutputStream os = new FileOutputStream(file);
            OutputStreamWriter out = new OutputStreamWriter(os);


            for (int i = 0; i < data.size(); ++i) {
                MeasurePoint m = data.get(i);
                out.write(m.getStoreString());
            }

            out.close();
        } catch (Throwable t) {
            throw (t);
        }
        return true;
    }

    private Point getAveragePoint() {
        float x = 0;
        float y = 0;
        float z = 0;
        
        for(int i = 0; i < accData.size(); ++i){
            Point p = accData.get(i);
            x += p.getX();
            y += p.getY();
            z += p.getZ();
        }
        
        return new Point(x, y, z, 1);
    }
    
    public float getLastSpeed(){
        return data.getLast().getSpeedAfter();
    }
    
    public float getLastSpeedKm(){
        float ms = getLastSpeed();
        return ms*3.6f;
    }
}

 

And, finally, how to use all this in your activity(I cleaned it up a lot, sorry if it will not complie - fill free to write it in comments:

  
public class TestActivity extends Activity {


    static final int TIMER_DONE = 2;
    static final int START = 3;
    static final int CAL_TIMER_DONE = 4;
    static final int ERROR = 5;

    private StartCatcher mStartListener;
    private XYZAccelerometer xyzAcc;
    private SensorManager mSensorManager;
    private static final long UPDATE_INTERVAL = 500;
    private static final long MEASURE_TIMES = 20;
    private Timer timer;
    private TextView tv;
    private Button testBtn;
    int counter;
    private MeasureData mdXYZ;


    /** handler for async events*/
    Handler hRefresh = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case TIMER_DONE:

                    onMeasureDone();
                    String es1 = Float.toString(Math.round(mdXYZ.getLastSpeedKm()*100)/100f);
                    tv.append(" END SPEED " + es1 + " " + es2 + " \n");
                    enableButtons();
                    break;
                case START:
                    tv.append(" START");
                    timer = new Timer();
                    timer.scheduleAtFixedRate(
                            new TimerTask() {

                                public void run() {
                                    dumpSensor();
                                }
                            },
                            0,
                            UPDATE_INTERVAL);

                    break;
                case ERROR:
                    Toast.makeText(getApplicationContext(), "ERROR", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        tv = (TextView) findViewById(R.id.txt);
        testBtn = (Button) findViewById(R.id.btn);
    }

    @Override
    protected void onResume() {
        super.onResume();
        tv.append("\n ..");
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        setAccelerometer();
        setStartCatcher();
        mSensorManager.registerListener(xyzAcc,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_GAME);
      
    }

    @Override
    protected void onPause() {
        mSensorManager.unregisterListener(xyzAcc);
        super.onPause();
    }


    public void onButtonTest(View v) {
        disableButtons();
        mdXYZ = new MeasureData(UPDATE_INTERVAL);
        counter = 0;
        tv.setText("");
        tv.append("Calibrating");
        Calibrator cal = new Calibrator(hRefresh, xyzAcc, START);
        cal.calibrate();
        
    }

    void dumpSensor() {
        ++counter;
        mdXYZ.addPoint(xyzAcc.getPoint());

        hRefresh.sendEmptyMessage(TICK);
          
        if (counter > MEASURE_TIMES) {
            timer.cancel();
            hRefresh.sendEmptyMessage(TIMER_DONE);
        }

    }

    private void enableButtons() {
        testBtn.setEnabled(true);

    }


    private void setAccelerometer() {
        xyzAcc = new XYZAccelerometer();
        mSensorManager.registerListener(xyzAcc,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_UI);
    }


    private void disableButtons() {
        testBtn.setEnabled(false);
    }

    private void onMeasureDone() {
        try {
            mdXYZ.process();
            long now = System.currentTimeMillis();
            mdXYZ.saveExt(this, Long.toString(now) + ".csv");
        } catch (Throwable ex) {
            Toast.makeText(this, ex.getMessage().toString(), Toast.LENGTH_SHORT);
        }
    }
}


<serviceLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <serviceButton 
        android:id="@+id/btn"
        android:text="TEST"
        android:layout_width="300px"
        android:layout_height="200px"
        android:onClick="onButtonTest"  />

        <serviceTextView  
    android:id = "@+id/txt"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text=":"
    />
<service/LinearLayout>


пятница, 19 августа 2011 г.

Android: AlarmManager and notification example





Let's talk about a task, that many application developers have to complete: notification user at time, specified by user, without using timer and service.

I suppose, that we already have got property "notifyTime" as a string value, (looks like "14:05"). I'll describe few steps, that we need to notify user everyday at specified time.

1. We need custom BroadcastReceiver class:
  
public class TimeNotification extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    // Talk about it later
    }
}
  
2. In main activity, let's realise following method:
  
 private void restartNotify() {
        // Alarm manager - magic thing that does what we need
        am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        // Intent for our  BroadcastReceiver 
        Intent intent = new Intent(this, TimeNotification.class);
        // PendingIntent for AlarmManager 
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
                intent, PendingIntent.FLAG_CANCEL_CURRENT );
        // Just in case we have already set up AlarmManager,
        // we do cancel.
        am.cancel(pendingIntent);

        //Some simple code to define time of notification:
        Calendar cal = Calendar.getInstance();
        Date stamp =  cal.getTime();
        int pos = notifyTime.indexOf(":");
        int hour = Integer.parseInt(notifyTime.substring(0, pos));
        int minute = Integer.parseInt(notifyTime.substring(pos+1));
        stamp.setHours(hour);
        stamp.setMinutes(minute);
        stamp.setSeconds(0);

        // In case it's too late notify user today
        if(stamp.getTime() < System.currentTimeMillis())
            stamp.setTime(stamp.getTime() + AlarmManager.INTERVAL_DAY);
                
        // Set one-time alarm
        am.set(AlarmManager.RTC_WAKEUP, stamp.getTime(), pendingIntent);
    }
  
Call this method in onStart() of main activity.
There is one not obvious thing: we could use am.setRepeat method with AlarmManager.INTERVAL_DAY interval. But user can change noification time preference anytime, so I decided to re-start alarm manager each time in BroadcastReceiver object. It is described in next step.

3. Fill onReceive method in TimeNotification
  
public void onReceive(Context context, Intent intent) {
        // Notification manager - we already know how to use it
        nm = (NotificationManager)        context.getSystemService(Context.NOTIFICATION_SERVICE);
        Notification notification = new Notification(R.drawable.icon, "Test", System.currentTimeMillis());
        // This is intent, we want to launch when user clicks on the notification.
        Intent intentTL = new Intent(context, MainActivity.class);
        notification.setLatestEventInfo(context, "Test", "Do something!",
                PendingIntent.getActivity(context, 0, intentTL,
                PendingIntent.FLAG_CANCEL_CURRENT));
        notification.flags = Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL;
        nm.notify(1, notification);
// Here we set next notification, in day interval
 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
                intent, PendingIntent.FLAG_CANCEL_CURRENT);
        am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + AlarmManager.INTERVAL_DAY, pendingIntent);
    }
  

4. Don't forget the main thing - add receiver to manifest file
  
    <receiver android:name=".TimeNotification" />
  

I hope that was useful!

среда, 17 августа 2011 г.

Android: Notification in your application (example).




Here we'll see how to make your application notify user to do something with it, even when it's off. Most of tutorials show notifications after click on the button or something like that, so - are useless, because it usually makes sense to notify user when application activity is not working.
Notification constructor has "when" parameter, notification builder has setWhen method. But the truth is, when you call NotificationManager.notify, notification appears immediately. "When" is used only to sort notifications.

I need to remind user to run my application periodically... One way I found is to make this - use service and timer (or AlarmManager, but it's next story).

So, the first step is - create service.
    
public class NotifyService extends Service {
    // Notification interval. 
    private static final long UPDATE_INTERVAL = 1000*60*60*24;

    private Timer timer = new Timer();

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        // we shedule task "showNotification" to run everyday.
        timer.scheduleAtFixedRate(
                new TimerTask() {
                    public void run() {
                        showNotification();
                    }
                },
                0,
                UPDATE_INTERVAL);
    }

    @Override
    public void onDestroy() {
    }

    @Override
    public void onStart(Intent intent, int startid) {
    }

    public void showNotification() {
// Here we are going do something...later
    }
}
Don't forget add information about service in your manifest file.
Inside "application" tag put

<service android:enabled="true" android:name="NotifyService" />
Then we should start service from activity. I suggest to do it in
"onStart" method:

public void onStart() {
  super.onStart();
  notifyService = new Intent(this, NotifyService.class);
  startService(notifyService);
       
}
To stop service, use simple code:

notifyService = new Intent(this, NotifyService.class);
stopService(notifyService);
Do not put it into onPause e t.c., because your service will die when application is closed, that's not what we want. Maybe you can offer user special button "Stop notifications", or, better, check option - it's up to you.
In this example I just let it live forever.

You can see if your service is working in the list of active applications on your phone - close activity window, active application should remain.

Now, let's add notification code - fill showNotification method of our service

public void showNotification() {
  NotificationManager mManager = 
    (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
  Notification notification = 
    new Notification(R.drawable.icon, "My App", System.currentTimeMillis());
  Intent intent = new Intent(this, MainActivity.class);
    notification.setLatestEventInfo(this, 
     "My App", 
     "Use me!",
      PendingIntent.getActivity(this.getBaseContext(), 
      0, 
      intent,
      PendingIntent.FLAG_CANCEL_CURRENT));
  notification.flags = Notification.DEFAULT_LIGHTS 
   | Notification.FLAG_AUTO_CANCEL;
  mManager.notify(1, notification);
}

Check it, must work!

P.S.
To notify a user in specified time requires some more logic in code above.
Also, there is a problem: some devices stop processors or reduce frequency, and timer does not work properly.
For long-period notifications, the right way is to use AlarmManager, I hope to write about it in my next post...